diff --git a/Makefile b/Makefile index 05c1cdc4..b0219efd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ include libtransistor.mk -libtransistor_TESTS := malloc bsd_ai_packing bsd sfdnsres nv helloworld hid hexdump args ssp stdin multiple_set_heap_size vi gpu display am sdl audio_output init_fini_arrays +libtransistor_TESTS := malloc bsd_ai_packing bsd sfdnsres nv helloworld hid hexdump args ssp stdin multiple_set_heap_size vi gpu display am sdl audio_output init_fini_arrays pthread getthreadid libtransistor_OBJECT_NAMES := crt0_common.o svc.o ipc.o tls.o util.o ipc/sm.o ipc/bsd.o ipc/nv.o ipc/hid.o ipc/ro.o ipc/nifm.o hid.o context.o ipc/vi.o display/binder.o display/parcel.o display/surface.o gpu/gpu.o ipc/am.o display/graphic_buffer_queue.o display/display.o gfx/blit.o ipc/time.o syscalls/syscalls.o syscalls/fd.o syscalls/sched.o syscalls/socket.o ipc/audio.o ipc/bpc.o libtransistor_OBJECT_FILES := $(addprefix $(LIBTRANSISTOR_HOME)/build/lib/,$(libtransistor_OBJECT_NAMES)) @@ -17,9 +17,12 @@ export AR_FOR_TARGET = $(AR) export RANLIB_FOR_TARGET = llvm-ranlib$(LLVM_POSTFIX) export CFLAGS_FOR_TARGET = $(CC_FLAGS) -Wno-unused-command-line-argument +# Everyone needs their cflags. +export CC_FLAGS + .SUFFIXES: # disable built-in rules -.PHONY: clean, clean_newlib, clean_compiler-rt, distclean +.PHONY: clean, clean_newlib, clean_compiler-rt, distclean all: $(LIBTRANSISTOR_HOME)/build/lib/libtransistor.nro.a \ $(LIBTRANSISTOR_HOME)/build/lib/libtransistor.nso.a \ @@ -48,12 +51,17 @@ $(LIBTRANSISTOR_HOME)/build/test/%.o: $(LIBTRANSISTOR_HOME)/test/%.c # Disable stack protector for crt0_common $(LIBTRANSISTOR_HOME)/build/lib/crt0_common.o: $(LIBTRANSISTOR_HOME)/lib/crt0_common.c + mkdir -p $(@D) + $(CC) $(CC_FLAGS) $(WARNINGS) -fno-stack-protector -Ipthread/ -Ipthread/sys/switch -c -o $@ $< + +# Don't instrument ipc.c, it might mess up the state +$(LIBTRANSISTOR_HOME)/build/lib/ipc.o: $(LIBTRANSISTOR_HOME)/lib/ipc.c mkdir -p $(@D) $(CC) $(CC_FLAGS) $(WARNINGS) -fno-stack-protector -c -o $@ $< $(LIBTRANSISTOR_HOME)/build/lib/%.o: $(LIBTRANSISTOR_HOME)/lib/%.c mkdir -p $(@D) - $(CC) $(CC_FLAGS) $(WARNINGS) -c -o $@ $< + $(CC) $(CC_FLAGS) $(WARNINGS) -finstrument-functions -c -o $@ $< $(LIBTRANSISTOR_HOME)/build/lib/%.o: $(LIBTRANSISTOR_HOME)/lib/%.S mkdir -p $(@D) @@ -84,6 +92,11 @@ $(LIBTRANSISTOR_HOME)/build/newlib/Makefile: $(LIBTRANSISTOR_HOME)/build/newlib/aarch64-none-switch/newlib/libc.a: $(LIBTRANSISTOR_HOME)/build/newlib/Makefile $(MAKE) -C $(LIBTRANSISTOR_HOME)/build/newlib/ +$(LIBTRANSISTOR_HOME)/pthread/libpthread.a: + $(MAKE) -C $(LIBTRANSISTOR_HOME)/pthread + +.PHONY: $(LIBTRANSISTOR_HOME)/pthread/libpthread.a + $(COMPILER_RT_BUILTINS_LIB): $(LIBTRANSISTOR_HOME)/build/compiler-rt/Makefile $(MAKE) -C $(LIBTRANSISTOR_HOME)/build/compiler-rt/ @@ -114,6 +127,7 @@ $(LIBTRANSISTOR_HOME)/build/sdl2/Makefile: clean: rm -rf $(LIBTRANSISTOR_HOME)/build/lib/* $(LIBTRANSISTOR_HOME)/build/test/* + $(MAKE) -C pthread clean clean_newlib: rm -rf build/newlib diff --git a/include/libtransistor/tls.h b/include/libtransistor/tls.h index 6857723d..0767596c 100644 --- a/include/libtransistor/tls.h +++ b/include/libtransistor/tls.h @@ -1,3 +1,16 @@ #pragma once -void *get_tls(); +#include + +struct thread_ctx { + struct _reent reent; + void *pthread; // Pointer to pthread internal structure +}; + +struct tls { + char ipc_buffer[0x100]; + char _unk1[0xF8]; + struct thread_ctx *ctx; +}; + +struct tls *get_tls(); diff --git a/lib/crt0_common.c b/lib/crt0_common.c index c40d04ef..224b9922 100644 --- a/lib/crt0_common.c +++ b/lib/crt0_common.c @@ -11,6 +11,7 @@ #include #include #include +#include int main(int argc, char **argv); @@ -158,7 +159,7 @@ static int bsslog_write(struct _reent *reent, void *v, const char *ptr, int len) static jmp_buf exit_jmpbuf; static int exit_value; - +static void *global_aslr_base; int _libtransistor_start(libtransistor_context_t *ctx, void *aslr_base) { if(relocate(aslr_base)) { return -4; @@ -169,6 +170,7 @@ int _libtransistor_start(libtransistor_context_t *ctx, void *aslr_base) { char *argv_default[] = {"contextless", NULL}; char **argv = argv_default; + global_aslr_base = aslr_base; int argc = 1; if(ctx != NULL) { @@ -181,27 +183,28 @@ int _libtransistor_start(libtransistor_context_t *ctx, void *aslr_base) { dbg_printf("invalid context magic"); return -2; } - + + if(ctx->version < 2 || ctx->version > LIBTRANSISTOR_CONTEXT_VERSION) { + dbg_printf("mismatched context version"); + return -2; + } + ctx->log_buffer = log_buffer; ctx->log_length = &log_length; ctx->return_flags = 0; - + argv = ctx->argv; argc = (int) ctx->argc; - if(ctx->version != LIBTRANSISTOR_CONTEXT_VERSION) { - dbg_printf("mismatched context version"); - return -2; - } - - if(ctx->size != sizeof(libtransistor_context_t)) { - dbg_printf("mismatched context size"); - return -3; - } memcpy(&libtransistor_context, ctx, ctx->size); + + if (ctx->version == 2) + libtransistor_context.main_thread = 0; } else { dbg_printf("no context"); + // Temporary fix to run this in Mephisto. + libtransistor_context.main_thread = 0xde00; if(svcSetHeapSize(&libtransistor_context.mem_base, DEFAULT_NOCONTEXT_HEAP_SIZE) != RESULT_OK) { dbg_printf("failed to set heap size"); return -5; @@ -209,6 +212,10 @@ int _libtransistor_start(libtransistor_context_t *ctx, void *aslr_base) { libtransistor_context.mem_size = DEFAULT_NOCONTEXT_HEAP_SIZE; } + dbg_printf("init threads"); + phal_tid tid = { .id = libtransistor_context.main_thread, .stack = NULL }; + _rthread_internal_init(tid); + dbg_printf("init stdio"); bsslog_stdout._write = bsslog_write; bsslog_stdout._flags = __SWR | __SNBF; @@ -238,7 +245,9 @@ int _libtransistor_start(libtransistor_context_t *ctx, void *aslr_base) { stdout = &bsslog_stdout; stderr = &bsslog_stdout; } + dbg_printf("set up stdout"); + printf("ASLR base %p\n", aslr_base); if(init_array != NULL) { if(init_array_size == -1) { @@ -248,7 +257,16 @@ int _libtransistor_start(libtransistor_context_t *ctx, void *aslr_base) { init_array[i](); } } - + + dbg_printf("init threads"); + if (libtransistor_context.main_thread != 0) { + phal_tid maintid; + maintid.id = libtransistor_context.main_thread; + maintid.stack = NULL; + _rthread_internal_init(maintid); + } else + dbg_printf("Ctx version doesn't support threading."); + int ret; if (setjmp(exit_jmpbuf) == 0) { ret = main(argc, argv); @@ -281,3 +299,61 @@ void _exit(int ret) { exit_value = ret; longjmp(exit_jmpbuf, 1); } + +char *ft_itoa(char buf[16], uintmax_t n, char *base) +{ + int i; + size_t base_len; + + i = 0; + base_len = strlen(base); + while (n > 0) + { + buf[i++] = base[n % base_len]; + n /= base_len; + } + i = 0; + while (i < 16 / 2) { + char c = buf[i]; + buf[i] = buf[15 - i]; + buf[15 - i] = c; + i++; + } + return (buf); +} + +static int in_cyg = 0; +void __cyg_profile_func_enter(void *des, void *src_call) { + if (in_cyg) + return; + in_cyg = 1; + + + char msg[] = "\nThread 0x0000000000000000 Entering function 0x0000000000000000 from 0x0000000000000000\n"; + + void *tid = get_tls(); + ft_itoa(msg + strlen("\nThread 0x"), tid, "0123456789ABCDEF"); + ft_itoa(msg + strlen("\nThread 0x0000000000000000 Entering function 0x"), des - global_aslr_base, "0123456789ABCDEF"); + ft_itoa(msg + strlen("\nThread 0x0000000000000000 Entering function 0x0000000000000000 from 0x"), src_call - global_aslr_base, "0123456789ABCDEF"); + if (bsd_get_object().object_id != 0 && libtransistor_context.has_bsd && libtransistor_context.std_socket > 0) { + bsd_send(libtransistor_context.std_socket, msg, strlen(msg), 0); + } + in_cyg = 0; +} + +void __cyg_profile_func_exit(void *des, void *src_call) { + if (in_cyg) + return; + in_cyg = 1; + + char msg[] = "\nThread 0x0000000000000000 Exit function 0x0000000000000000 to 0x0000000000000000\n"; + + void *tid = get_tls(); + ft_itoa(msg + strlen("\nThread 0x"), tid, "0123456789ABCDEF"); + ft_itoa(msg + strlen("\nThread 0x0000000000000000 Exit function 0x"), des - global_aslr_base, "0123456789ABCDEF"); + ft_itoa(msg + strlen("\nThread 0x0000000000000000 Exit function 0x0000000000000000 to 0x"), src_call - global_aslr_base, "0123456789ABCDEF"); + if (bsd_get_object().object_id != 0 && libtransistor_context.has_bsd && libtransistor_context.std_socket > 0) { + bsd_send(libtransistor_context.std_socket, msg, strlen(msg), 0); + } + in_cyg = 0; +} diff --git a/lib/syscalls/syscalls.c b/lib/syscalls/syscalls.c index ae8498f7..3d87d7cb 100644 --- a/lib/syscalls/syscalls.c +++ b/lib/syscalls/syscalls.c @@ -8,13 +8,23 @@ #include #include #include +#include +#include #include #include #include void _exit(); // implemented in libtransistor crt0 +struct _reent *__getreent() { + struct tls *tls = get_tls(); + if (tls == NULL || tls->ctx == NULL) + return NULL; + else + return &tls->ctx->reent; +} + int _close_r(struct _reent *reent, int file) { int res = fd_close(file); if (res < 0) { @@ -26,7 +36,7 @@ int _close_r(struct _reent *reent, int file) { char *_environ[] = {NULL}; -int _execve_r(struct _reent *reent, char *name, char **argv, char **env) { +int _execve_r(struct _reent *reent, const char *name, char *const *argv, char *const *env) { reent->_errno = ENOSYS; return -1; } @@ -56,12 +66,12 @@ int _kill_r(struct _reent *reent, int pid, int sig) { return -1; } -int _link_r(struct _reent *reent, char *old, char *new) { +int _link_r(struct _reent *reent, const char *old, const char *new) { reent->_errno = ENOSYS; return -1; } -int _lseek_r(struct _reent *reent, int file, int pos, int whence) { +off_t _lseek_r(struct _reent *reent, int file, off_t pos, int whence) { ssize_t res = 0; struct file *f = fd_file_get(file); @@ -84,12 +94,12 @@ int _lseek_r(struct _reent *reent, int file, int pos, int whence) { return res; } -int _open_r(struct _reent *reent, const char *name, int flags, ...) { +int _open_r(struct _reent *reent, const char *name, int flags, int mode) { reent->_errno = ENOSYS; return -1; } -int _read_r(struct _reent *reent, int file, char *ptr, int len) { +ssize_t _read_r(struct _reent *reent, int file, void *ptr, size_t len) { ssize_t res = 0; struct file *f = fd_file_get(file); @@ -102,7 +112,7 @@ int _read_r(struct _reent *reent, int file, char *ptr, int len) { res = -ENOSYS; goto finalize; } - res = f->ops->read(f->data, ptr, len); + res = f->ops->read(f->data, (char*)ptr, len); finalize: fd_file_put(f); if (res < 0) { @@ -114,7 +124,7 @@ int _read_r(struct _reent *reent, int file, char *ptr, int len) { static size_t data_size = 0; -caddr_t _sbrk_r(struct _reent *reent, int incr) { +void *_sbrk_r(struct _reent *reent, ptrdiff_t incr) { if(data_size + incr > libtransistor_context.mem_size) { reent->_errno = ENOMEM; return (void*) -1; @@ -136,7 +146,7 @@ clock_t _times_r(struct _reent *reent, struct tms *buf) { return (clock_t) -1; } -int _unlink_r(struct _reent *reent, char *name) { +int _unlink_r(struct _reent *reent, const char *name) { reent->_errno = ENOSYS; return -1; } @@ -146,7 +156,7 @@ int _wait_r(struct _reent *reent, int *status) { return -1; } -int _write_r(struct _reent *reent, int file, char *ptr, int len) { +ssize_t _write_r(struct _reent *reent, int file, const void *ptr, size_t len) { ssize_t res = 0; struct file *f = fd_file_get(file); @@ -159,7 +169,7 @@ int _write_r(struct _reent *reent, int file, char *ptr, int len) { res = -ENOSYS; goto finalize; } - res = f->ops->write(f->data, ptr, len); + res = f->ops->write(f->data, (char*)ptr, len); finalize: fd_file_put(f); if (res < 0) { diff --git a/libtransistor.mk b/libtransistor.mk index 6305d82f..97fac050 100644 --- a/libtransistor.mk +++ b/libtransistor.mk @@ -4,7 +4,7 @@ else LIBTRANSISTOR_HOME := $(realpath $(LIBTRANSISTOR_HOME)) endif -SYS_INCLUDES := -isystem $(LIBTRANSISTOR_HOME)/newlib/newlib/libc/include/ -isystem $(LIBTRANSISTOR_HOME)/newlib/newlib/libc/sys/switch/include/ +SYS_INCLUDES := -isystem $(LIBTRANSISTOR_HOME)/pthread/include -isystem $(LIBTRANSISTOR_HOME)/newlib/newlib/libc/include/ -isystem $(LIBTRANSISTOR_HOME)/newlib/newlib/libc/sys/switch/include/ INCLUDES := $(SYS_INCLUDES) -I$(LIBTRANSISTOR_HOME)/include/ -I $(LIBTRANSISTOR_HOME)/build/sdl2_install/include/ WARNINGS := -Wall -Wextra -Werror-implicit-function-declaration -Wno-unused-parameter -Wno-unused-command-line-argument @@ -23,7 +23,7 @@ PYTHON2 := python2 MEPHISTO := ctu RUBY := ruby COMPILER_RT_BUILTINS_LIB := $(LIBTRANSISTOR_HOME)/build/compiler-rt/lib/linux/libclang_rt.builtins-aarch64.a -LIBTRANSISTOR_COMMON_LIBS := $(LIBTRANSISTOR_HOME)/build/newlib/aarch64-none-switch/newlib/libc.a $(COMPILER_RT_BUILTINS_LIB) $(LIBTRANSISTOR_HOME)/build/sdl2_install/lib/libSDL2.a +LIBTRANSISTOR_COMMON_LIBS := $(LIBTRANSISTOR_HOME)/build/newlib/aarch64-none-switch/newlib/libc.a $(COMPILER_RT_BUILTINS_LIB) $(LIBTRANSISTOR_HOME)/build/sdl2_install/lib/libSDL2.a $(LIBTRANSISTOR_HOME)/pthread/libpthread.a LIBTRANSISTOR_NRO_LIB := $(LIBTRANSISTOR_HOME)/build/lib/libtransistor.nro.a LIBTRANSISTOR_NSO_LIB := $(LIBTRANSISTOR_HOME)/build/lib/libtransistor.nso.a LIBTRANSISTOR_NRO_LDFLAGS := --whole-archive $(LIBTRANSISTOR_NRO_LIB) --no-whole-archive $(LIBTRANSISTOR_COMMON_LIBS) diff --git a/pthread/Makefile b/pthread/Makefile new file mode 100644 index 00000000..315da54c --- /dev/null +++ b/pthread/Makefile @@ -0,0 +1,51 @@ +# $OpenBSD: Makefile,v 1.49 2017/10/15 23:40:33 guenther Exp $ + +NAME=libpthread.a + +#CFLAGS+=-Wall -g -Werror -Wshadow +CC_FLAGS += -Werror-implicit-function-declaration -finstrument-functions +#CFLAGS+=-Wsign-compare +CC_FLAGS += -Isys/switch/ -I. + +LDADD = -Wl,-znodelete +SRCS= rthread_attr.c \ + rthread_barrier.c \ + rthread_barrier_attr.c \ + rthread_cleanup.c \ + rthread_cond.c \ + rthread_condattr.c \ + rthread_debug.c \ + rthread_getcpuclockid.c \ + rthread_internal.c \ + rthread_mutex.c \ + rthread_mutex_prio.c \ + rthread_mutexattr.c \ + rthread_once.c \ + rthread_rwlock.c \ + rthread_rwlockattr.c \ + rthread_sched.c \ + rthread_sem.c \ + rthread_sig.c \ + rthread_spin_lock.c \ + rthread_thread.c \ + rthread_tls.c \ + sched_prio.c \ + sys/switch/phal.c + #rthread_stack.c \ + #rthread_file.c \ + #rthread_libc.c \ + # Seems to be an alternative implementation of mutex ? + #rthread_sync.c \ + +OBJS = $(SRCS:.c=.o) + +all: $(NAME) + +%.o: %.c + $(CC) $(CC_FLAGS) -c -o $@ $< + +$(NAME): $(OBJS) + $(AR) rcs $(NAME) $(OBJS) + +clean: + rm -f $(OBJS) $(NAME) diff --git a/pthread/README.md b/pthread/README.md new file mode 100644 index 00000000..28f4b9e3 --- /dev/null +++ b/pthread/README.md @@ -0,0 +1,4 @@ +# Pthread HAL + +Pthread-HAL is a pthread implementation based on OpenBSD's `rthread`, that tries +to abstract away platform differences to be as easily portable as possible. diff --git a/pthread/Symbols.map b/pthread/Symbols.map new file mode 100644 index 00000000..a7aa4ce4 --- /dev/null +++ b/pthread/Symbols.map @@ -0,0 +1,102 @@ +{ + global: + /* pthread implementation */ + pthread_attr_destroy; + pthread_attr_getdetachstate; + pthread_attr_getguardsize; + pthread_attr_getinheritsched; + pthread_attr_getschedparam; + pthread_attr_getschedpolicy; + pthread_attr_getscope; + pthread_attr_getstack; + pthread_attr_getstackaddr; + pthread_attr_getstacksize; + pthread_attr_init; + pthread_attr_setdetachstate; + pthread_attr_setguardsize; + pthread_attr_setinheritsched; + pthread_attr_setschedparam; + pthread_attr_setschedpolicy; + pthread_attr_setscope; + pthread_attr_setstack; + pthread_attr_setstackaddr; + pthread_attr_setstacksize; + pthread_barrier_destroy; + pthread_barrier_init; + pthread_barrier_wait; + pthread_barrierattr_destroy; + pthread_barrierattr_getpshared; + pthread_barrierattr_init; + pthread_barrierattr_setpshared; + pthread_cancel; + pthread_cleanup_pop; + pthread_cleanup_push; + pthread_create; + pthread_detach; + pthread_getconcurrency; + pthread_getcpuclockid; + pthread_getprio; + pthread_getschedparam; + pthread_join; + pthread_kill; + pthread_main_np; + pthread_mutex_getprioceiling; + pthread_mutex_setprioceiling; + pthread_mutexattr_destroy; + pthread_mutexattr_getkind_np; + pthread_mutexattr_getprioceiling; + pthread_mutexattr_getprotocol; + pthread_mutexattr_gettype; + pthread_mutexattr_init; + pthread_mutexattr_setkind_np; + pthread_mutexattr_setprioceiling; + pthread_mutexattr_setprotocol; + pthread_mutexattr_settype; + pthread_rwlock_destroy; + pthread_rwlock_init; + pthread_rwlock_rdlock; + pthread_rwlock_timedrdlock; + pthread_rwlock_timedwrlock; + pthread_rwlock_tryrdlock; + pthread_rwlock_trywrlock; + pthread_rwlock_unlock; + pthread_rwlock_wrlock; + pthread_rwlockattr_destroy; + pthread_rwlockattr_getpshared; + pthread_rwlockattr_init; + pthread_rwlockattr_setpshared; + pthread_set_name_np; + pthread_setcancelstate; + pthread_setcanceltype; + pthread_setconcurrency; + pthread_setprio; + pthread_setschedparam; + pthread_spin_destroy; + pthread_spin_init; + pthread_spin_lock; + pthread_spin_trylock; + pthread_spin_unlock; + pthread_stackseg_np; + pthread_testcancel; + pthread_yield; + sched_get_priority_max; + sched_get_priority_min; + sem_close; + sem_destroy; + sem_getvalue; + sem_init; + sem_open; + sem_post; + sem_timedwait; + sem_trywait; + sem_unlink; + sem_wait; + sigwait; + + /* used for debugging & regress */ + _thread_dump_info; + + _dlctl; + local: + *; +}; diff --git a/pthread/atfork.c b/pthread/atfork.c new file mode 100644 index 00000000..7d3222f4 --- /dev/null +++ b/pthread/atfork.c @@ -0,0 +1,73 @@ +/* $OpenBSD: atfork.c,v 1.3 2017/08/15 06:38:41 guenther Exp $ */ + +/* + * Copyright (c) 2008 Kurt Miller + * Copyright (c) 2008 Philip Guenther + * Copyright (c) 2003 Daniel Eischen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: /repoman/r/ncvs/src/lib/libc_r/uthread/uthread_atfork.c,v 1.1 2004/12/10 03:36:45 grog Exp $ + */ + +#include +#include +#include + +#include "thread_private.h" +#include "atfork.h" + +int _thread_atfork(void (*_prepare)(void), void (*_parent)(void), + void (*_child)(void), void *_dso); +PROTO_NORMAL(_thread_atfork); + +int +_thread_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void), void *dso) +{ + struct atfork_fn *af; + + if ((af = malloc(sizeof *af)) == NULL) + return (ENOMEM); + + af->fn_prepare = prepare; + af->fn_parent = parent; + af->fn_child = child; + af->fn_dso = dso; + _ATFORK_LOCK(); + TAILQ_INSERT_TAIL(&_atfork_list, af, fn_next); + _ATFORK_UNLOCK(); + return (0); +} +DEF_STRONG(_thread_atfork); + +/* + * Copy of pthread_atfork() used by libc and anything staticly linked + * into the executable. This passes NULL for the dso, so the callbacks + * are never removed by dlclose() + */ +int +pthread_atfork(void (*prep)(void), void (*parent)(void), void (*child)(void)) +{ + return (_thread_atfork(prep, parent, child, NULL)); +} diff --git a/pthread/callbacks.c b/pthread/callbacks.c new file mode 100644 index 00000000..e38cf205 --- /dev/null +++ b/pthread/callbacks.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 Philip Guenther + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include "thread_private.h" +#include "rthread_cb.h" + +static __dead void +_thread_canceled(void) +{ + pthread_exit(PTHREAD_CANCELED); +} + +void +_thread_set_callbacks(const struct thread_callbacks *cb, size_t len) +{ + sigset_t allmask, omask; + + if (sizeof(*cb) != len) { + fprintf(stderr, "library mismatch: libc expected %zu but" + " libpthread gave %zu\n", sizeof(*cb), len); + fflush(stderr); + _exit(44); + } + + sigfillset(&allmask); + if (sigprocmask(SIG_BLOCK, &allmask, &omask) == 0) { + /* mprotect RW */ + memcpy(&_thread_cb, cb, sizeof(_thread_cb)); + + /* + * These are supplied by libc, but only enabled + * here when we actually need to prep for doing MT. + */ + _thread_cb.tc_canceled = _thread_canceled; + _thread_cb.tc_flockfile = _thread_flockfile; + _thread_cb.tc_ftrylockfile = _thread_ftrylockfile; + _thread_cb.tc_funlockfile = _thread_funlockfile; + _thread_cb.tc_malloc_lock = _thread_malloc_lock; + _thread_cb.tc_malloc_unlock = _thread_malloc_unlock; + _thread_cb.tc_atexit_lock = _thread_atexit_lock; + _thread_cb.tc_atexit_unlock = _thread_atexit_unlock; + _thread_cb.tc_atfork_lock = _thread_atfork_lock; + _thread_cb.tc_atfork_unlock = _thread_atfork_unlock; + _thread_cb.tc_arc4_lock = _thread_arc4_lock; + _thread_cb.tc_arc4_unlock = _thread_arc4_unlock; + _thread_cb.tc_mutex_lock = _thread_mutex_lock; + _thread_cb.tc_mutex_unlock = _thread_mutex_unlock; + _thread_cb.tc_mutex_destroy = _thread_mutex_destroy; + _thread_cb.tc_tag_lock = _thread_tag_lock; + _thread_cb.tc_tag_unlock = _thread_tag_unlock; + _thread_cb.tc_tag_storage = _thread_tag_storage; + + /* mprotect RO | LOCKPERM | NOUNMAP */ + sigprocmask(SIG_SETMASK, &omask, NULL); + } +} diff --git a/pthread/phal.h b/pthread/phal.h new file mode 100644 index 00000000..714f490f --- /dev/null +++ b/pthread/phal.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +int phal_thread_create(phal_tid *tid, void (*start_routine)(void*), void *arg); +void phal_thread_exit(phal_tid *tid); + +// Called after the thread exited, to free up any potential resources +int phal_thread_destroy(phal_tid *tid); +void **phal_get_tls(); + +int phal_semaphore_create(phal_semaphore *sem); +int phal_semaphore_destroy(phal_semaphore *sem); + +/// Lock the semaphore. +int phal_semaphore_lock(phal_semaphore *sem); +int phal_semaphore_unlock(phal_semaphore *sem); + +int phal_semaphore_signal(phal_semaphore *sem); +int phal_semaphore_broadcast(phal_semaphore *sem); + +/// Wait for the semaphore to be signaled. Note that we should **not** wake up +/// if a signal was previously sent. This is not a counting semaphore. +/// This should be called with the semaphore locked ! It will unlock the +/// semaphore when it goes to sleep, and lock it when it wakes up. The lock must +/// also be held when signaling/broadcasting the semaphore. This prevents race +/// conditions from occuring. +int phal_semaphore_wait(phal_semaphore *sem, const struct timespec *abs); + +// TODO: pass timespec instead +int phal_thread_sleep(uint64_t msec); diff --git a/pthread/rthread.h b/pthread/rthread.h new file mode 100644 index 00000000..c5ebe6cc --- /dev/null +++ b/pthread/rthread.h @@ -0,0 +1,117 @@ +/* $OpenBSD: rthread.h,v 1.63 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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. + * + * Do not reorder _atomic_lock_t and sem_t variables in the structs. + * This is due to alignment requirements of certain arches like hppa. + * The current requirement is 16 bytes. + * + * THE MACHINE DEPENDENT CERROR CODE HAS HARD CODED OFFSETS INTO PTHREAD_T! + */ + +#ifndef _RTHREAD_H_ +#define _RTHREAD_H_ + +void _rthread_tls_destructors(pthread_t); +void _rthread_release(pthread_t); +extern int _rthread_debug_level; +extern struct pthread _initial_thread; + +// Will probably go to newlib eventually +#include "semaphore.h" +#include "thread_private.h" + +#ifdef __LP64__ +#define RTHREAD_STACK_SIZE_DEF (512 * 1024) +#else +#define RTHREAD_STACK_SIZE_DEF (256 * 1024) +#endif + +struct stack { + SLIST_ENTRY(stack) link; /* link for free default stacks */ + void *sp; /* machine stack pointer */ + void *base; /* bottom of allocated area */ + size_t guardsize; /* size of PROT_NONE zone or */ + /* ==1 if application alloced */ + size_t len; /* total size of allocated stack */ +}; + +#define PTHREAD_MIN_PRIORITY 0 +#define PTHREAD_MAX_PRIORITY 31 + + +struct pthread_rwlock { + _atomic_lock_t lock; + pthread_t owner; + struct pthread_queue writers; + int readers; +}; + +struct pthread_rwlockattr { + int pshared; +}; + +struct pthread_barrier { + pthread_mutex_t mutex; + pthread_cond_t cond; + int threshold; + int in; + int out; + int generation; +}; + +struct pthread_barrierattr { + int pshared; +}; + +struct pthread_spinlock { + _atomic_lock_t lock; + pthread_t owner; +}; + + +#define ROUND_TO_PAGE(size) \ + (((size) + (_thread_pagesize - 1)) & ~(_thread_pagesize - 1)) + +int _sem_wait(sem_t, int, const struct timespec *, int *); +int _sem_post(sem_t); + +void _rthread_init(void); +void _rthread_internal_init(phal_tid tid); +struct stack *_rthread_alloc_stack(pthread_t); +void _rthread_free_stack(struct stack *); +#if 0 +#ifndef NO_PIC +void _rthread_dl_lock(int what); +#endif +#endif + +extern int _threads_ready; +extern size_t _thread_pagesize; +extern LIST_HEAD(listhead, pthread) _thread_list; +extern _atomic_lock_t _thread_lock; +extern struct pthread_attr _rthread_attr_default; + +void _thread_dump_info(void); + +#define REDIRECT_SYSCALL(x) typeof(x) x asm("_thread_sys_"#x) + +#endif /* _RTHREAD_H_ */ diff --git a/pthread/rthread_attr.c b/pthread/rthread_attr.c new file mode 100644 index 00000000..a915e175 --- /dev/null +++ b/pthread/rthread_attr.c @@ -0,0 +1,195 @@ +/* $OpenBSD: rthread_attr.c,v 1.23 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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 +#include +#include +#include + +#include + +#include "rthread.h" + +/* + * Note: stack_size + guard_size == total stack used + * + * pthread_attr_init MUST be called before any other attribute function + * for proper operation. + * + * Every call to pthread_attr_init MUST be matched with a call to + * pthread_attr_destroy to avoid leaking memory. This is an implementation + * requirement, not a POSIX requirement. + */ + +int +pthread_attr_init(pthread_attr_t *attrp) +{ + pthread_attr_t attr; + + /* make sure _rthread_attr_default has been initialized */ + if (!_threads_ready) + _rthread_init(); + + attr = calloc(1, sizeof(*attr)); + if (!attr) + return (errno); + *attr = _rthread_attr_default; + *attrp = attr; + + return (0); +} + +int +pthread_attr_destroy(pthread_attr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +int +pthread_attr_getguardsize(const pthread_attr_t *attrp, size_t *guardsize) +{ + *guardsize = (*attrp)->guard_size; + + return (0); +} + +int +pthread_attr_setguardsize(pthread_attr_t *attrp, size_t guardsize) +{ + (*attrp)->guard_size = guardsize; + + 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) +{ + int error; + + error = (detachstate == PTHREAD_CREATE_DETACHED || + detachstate == PTHREAD_CREATE_JOINABLE) ? 0 : EINVAL; + if (error == 0) + (*attrp)->detach_state = detachstate; + + return (error); +} + +int +pthread_attr_getstack(const pthread_attr_t *attrp, void **stackaddr, + size_t *stacksize) +{ + *stackaddr = (*attrp)->stack_addr; + *stacksize = (*attrp)->stack_size; + + return (0); +} + +int +pthread_attr_setstack(pthread_attr_t *attrp, void *stackaddr, size_t stacksize) +{ + int error; + + /* + * XXX Add an alignment test, on stackaddr for stack-grows-up + * archs or on stackaddr+stacksize for stack-grows-down archs + */ + if (stacksize < PTHREAD_STACK_MIN) + return (EINVAL); + if ((error = pthread_attr_setstackaddr(attrp, stackaddr))) + return (error); + (*attrp)->stack_size = stacksize; + + 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) +{ + if (!_threads_ready) /* for ROUND_TO_PAGE */ + _rthread_init(); + + if (stacksize < PTHREAD_STACK_MIN || + stacksize > ROUND_TO_PAGE(stacksize)) + return (EINVAL); + (*attrp)->stack_size = stacksize; + + return (0); +} + +int +pthread_attr_getstackaddr(const pthread_attr_t *attrp, void **stackaddr) +{ + *stackaddr = (*attrp)->stack_addr; + + return (0); +} + +int +pthread_attr_setstackaddr(pthread_attr_t *attrp, void *stackaddr) +{ + if (!_threads_ready) + _rthread_init(); /* for _thread_pagesize */ + + if (stackaddr == NULL || (uintptr_t)stackaddr & (_thread_pagesize - 1)) + return (EINVAL); + (*attrp)->stack_addr = stackaddr; + + 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) +{ + if (contentionscope != PTHREAD_SCOPE_SYSTEM && + contentionscope != PTHREAD_SCOPE_PROCESS) + return (EINVAL); + (*attrp)->contention_scope = contentionscope; + + return (0); +} + diff --git a/pthread/rthread_barrier.c b/pthread/rthread_barrier.c new file mode 100644 index 00000000..7ecdb1f4 --- /dev/null +++ b/pthread/rthread_barrier.c @@ -0,0 +1,143 @@ +/* $OpenBSD: rthread_barrier.c,v 1.3 2016/04/15 17:54:17 tedu Exp $ */ +/* + * Copyright (c) 2012 Paul Irofti + * + * Permission to use, copy, modify, and/or 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. + */ + +#include +#include + +#include + +#include "rthread.h" + +int +pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr, + unsigned int count) { + int rc = 0; + pthread_barrier_t b = NULL; + + if (barrier == NULL) + return (EINVAL); + + if (attr != NULL) { + if (*attr == NULL) + return (EINVAL); + + if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE) + return (ENOTSUP); + } + + b = calloc(1, sizeof *b); + if (b == NULL) + return (ENOMEM); + + if ((rc = pthread_mutex_init(&b->mutex, NULL))) + goto err; + if ((rc = pthread_cond_init(&b->cond, NULL))) + goto err; + + b->threshold = count; + + *barrier = b; + + return (0); + +err: + if (b) { + if (b->mutex) + pthread_mutex_destroy(&b->mutex); + if (b->cond) + pthread_cond_destroy(&b->cond); + free(b); + } + + return (rc); +} + +int +pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + int rc; + pthread_barrier_t b; + + if (barrier == NULL || *barrier == NULL) + return (EINVAL); + + if ((rc = pthread_mutex_lock(&(*barrier)->mutex))) + return (rc); + + b = *barrier; + + if (b->out > 0 || b->in > 0) { + pthread_mutex_unlock(&b->mutex); + return (EBUSY); + } + + *barrier = NULL; + pthread_mutex_unlock(&b->mutex); + pthread_mutex_destroy(&b->mutex); + pthread_cond_destroy(&b->cond); + free(b); + return (0); +} + +int +pthread_barrier_wait(pthread_barrier_t *barrier) +{ + pthread_barrier_t b; + int rc, old_state, gen; + int done = 0; + + if (barrier == NULL || *barrier == NULL) + return (EINVAL); + + if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state))) + return (rc); + + b = *barrier; + if ((rc = pthread_mutex_lock(&b->mutex))) + goto cancel; + + _rthread_debug(6, "in: %d, threshold: %d\n", b->in, b->threshold); + if (++b->in == b->threshold) { + b->out = b->in - 1; + b->in = 0; + b->generation++; + if ((rc = pthread_cond_signal(&b->cond))) + goto err; + done = 1; + _rthread_debug(6, "threshold reached\n"); + } else { + gen = b->generation; + _rthread_debug(6, "waiting on condition\n"); + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex))) + goto err; + } while (gen == b->generation); + b->out--; /* mark thread exit */ + if ((rc = pthread_cond_signal(&b->cond))) + goto err; + } + +err: + if ((rc = pthread_mutex_unlock(&b->mutex))) + return (rc); +cancel: + rc = pthread_setcancelstate(old_state, NULL); + if (rc == 0 && done) + rc = PTHREAD_BARRIER_SERIAL_THREAD; + + return (rc); +} diff --git a/pthread/rthread_barrier_attr.c b/pthread/rthread_barrier_attr.c new file mode 100644 index 00000000..5d51e1dc --- /dev/null +++ b/pthread/rthread_barrier_attr.c @@ -0,0 +1,73 @@ +/* $OpenBSD: rthread_barrier_attr.c,v 1.2 2012/04/23 08:30:33 pirofti Exp $ */ +/* + * Copyright (c) 2012 Paul Irofti + * + * Permission to use, copy, modify, and/or 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. + */ + +#include +#include + +#include + +#include "rthread.h" + +int +pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + if (attr == NULL) + return (EINVAL); + + *attr = calloc(1, sizeof **attr); + if (*attr == NULL) + return (ENOMEM); + + (*attr)->pshared = PTHREAD_PROCESS_PRIVATE; + + return (0); +} + +int +pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + free(*attr); + return (0); +} + +int +pthread_barrierattr_getpshared(pthread_barrierattr_t *attr, int *pshared) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + *pshared = (*attr)->pshared; + + return (0); +} + +int +pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + if (attr == NULL || *attr == NULL) + return (EINVAL); + + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (ENOTSUP); + + (*attr)->pshared = pshared; + + return (0); +} diff --git a/pthread/rthread_cleanup.c b/pthread/rthread_cleanup.c new file mode 100644 index 00000000..e69de29b diff --git a/pthread/rthread_cond.c b/pthread/rthread_cond.c new file mode 100644 index 00000000..4b87e6a1 --- /dev/null +++ b/pthread/rthread_cond.c @@ -0,0 +1,220 @@ +/* $OpenBSD: rthread_cond.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2017 Martin Pieuchot + * Copyright (c) 2012 Philip Guenther + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rthread.h" +#include "synch.h" + +int +pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr) +{ + pthread_cond_t cond; + + cond = calloc(1, sizeof(*cond)); + if (cond == NULL) + return (ENOMEM); + + if (attr == NULL) + cond->clock = CLOCK_REALTIME; + else + cond->clock = (*attr)->ca_clock; + phal_semaphore_create(&cond->sem); + *condp = cond; + + return (0); +} + +int +pthread_cond_destroy(pthread_cond_t *condp) +{ + pthread_cond_t cond; + + assert(condp != NULL); + cond = *condp; + + if (cond != NULL) { + if (cond->mutex != NULL) { +#define MSG "pthread_cond_destroy on condvar with waiters!\n" + write(2, MSG, sizeof(MSG) - 1); +#undef MSG + return (EBUSY); + } + free(cond); + } + *condp = NULL; + + return (0); +} + +int +_rthread_cond_timedwait(pthread_cond_t cond, pthread_mutex_t *mutexp, + const struct timespec *abs) +{ + struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; + pthread_t self = pthread_self(); + int error, rv = 0, canceled = 0, mutex_count = 0; + clockid_t clock = cond->clock; + //int seq = cond->seq; + //PREP_CANCEL_POINT(tib); + + _rthread_debug(5, "%p: cond_timed %p,%p (%p)\n", self, + (void *)cond, (void *)mutex, (void *)mutex->owner); + + //ENTER_DELAYED_CANCEL_POINT(tib, self); + +#if notyet + /* mark the condvar as being associated with this mutex */ + if (cond->mutex == NULL) + atomic_cas_ptr(&cond->mutex, NULL, mutex); + + if (cond->mutex != mutex) { + LEAVE_CANCEL_POINT_INNER(tib, 1); + return (EINVAL); + } +#endif + + /* snag the count in case this is a recursive mutex */ + if (mutex->type == PTHREAD_MUTEX_RECURSIVE) + mutex_count = mutex->count; + + // Lock the semaphore now, and unlock user mutex then. + // This ensures the atomicity of thread wakeups. + phal_semaphore_lock(&cond->sem); + + pthread_mutex_unlock(mutexp); + + do { + /* If ``seq'' wraps you deserve to lose a signal. */ + error = phal_semaphore_wait(&cond->sem, abs); + /* + * If we took a normal signal (not from cancellation) then + * we should just go back to sleep without changing state + * (timeouts, etc). + */ + } while ((error == EINTR) && + (self->tib_canceled == 0 || (self->tib_cantcancel & CANCEL_DISABLED))); + + /* if timeout or canceled, make note of that */ + if (error == EINTR) + canceled = 1; + else + rv = error; + + pthread_mutex_lock(mutexp); + phal_semaphore_unlock(&cond->sem); + + /* restore the mutex's count */ + if (mutex->type == PTHREAD_MUTEX_RECURSIVE) + mutex->count = mutex_count; + + //LEAVE_CANCEL_POINT_INNER(tib, canceled); + + return rv; +} + +int +pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, + const struct timespec *abs) +{ + pthread_cond_t cond; + int error; + + if (*condp == NULL) { + if ((error = pthread_cond_init(condp, NULL))) + return (error); + } + + cond = *condp; + if (abs == NULL || abs->tv_sec < 0 || abs->tv_nsec < 0 || + abs->tv_nsec >= 1000000000) + return (EINVAL); + + return (_rthread_cond_timedwait(cond, mutexp, abs)); +} + +int +pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) +{ + pthread_cond_t cond; + int error; + + if (*condp == NULL) { + if ((error = pthread_cond_init(condp, NULL))) + return (error); + } + + cond = *condp; + return (_rthread_cond_timedwait(cond, mutexp, NULL)); +} + +int +pthread_cond_signal(pthread_cond_t *condp) +{ + pthread_cond_t cond; + int count; + + if (*condp == NULL) + return (0); + + cond = *condp; + + //cond->seq++; + phal_semaphore_lock(&cond->sem); + phal_semaphore_signal(&cond->sem); + phal_semaphore_unlock(&cond->sem); + count = 1; // We don't know :shrug: + + _rthread_debug(5, "%p: cond_signal %p, %d awaken\n", pthread_self(), + (void *)cond, count); + + return (0); +} + +int +pthread_cond_broadcast(pthread_cond_t *condp) +{ + pthread_cond_t cond; + int count; + + if (*condp == NULL) + return (0); + + cond = *condp; + + //cond->seq++; +#if notyet + count = _requeue(&cond->seq, 1, INT_MAX, &cond->mutex->lock); +#else + phal_semaphore_lock(&cond->sem); + phal_semaphore_broadcast(&cond->sem); + phal_semaphore_unlock(&cond->sem); + count = 0; // We don't know :shrug: +#endif + + _rthread_debug(5, "%p: cond_broadcast %p, %d awaken\n", pthread_self(), + (void *)cond, count); + + return (0); +} diff --git a/pthread/rthread_condattr.c b/pthread/rthread_condattr.c new file mode 100644 index 00000000..8d6ba771 --- /dev/null +++ b/pthread/rthread_condattr.c @@ -0,0 +1,68 @@ +/* $OpenBSD: rthread_condattr.c,v 1.3 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * Copyright (c) 2012 Philip Guenther + * 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. + */ +/* + * Condition Variable Attributes + */ + +#include +#include +#include +#include + +#include "rthread.h" + +int +pthread_condattr_init(pthread_condattr_t *attrp) +{ + pthread_condattr_t attr; + + attr = calloc(1, sizeof(*attr)); + if (!attr) + return (errno); + attr->ca_clock = CLOCK_REALTIME; + *attrp = attr; + + return (0); +} + +int +pthread_condattr_destroy(pthread_condattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +int +pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id) +{ + *clock_id = (*attr)->ca_clock; + return (0); +} + +int +pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id) +{ + if (clock_id != CLOCK_REALTIME/* && clock_id != CLOCK_MONOTONIC*/) + return (EINVAL); + (*attr)->ca_clock = clock_id; + return (0); +} + diff --git a/pthread/rthread_debug.c b/pthread/rthread_debug.c new file mode 100644 index 00000000..68390216 --- /dev/null +++ b/pthread/rthread_debug.c @@ -0,0 +1,26 @@ +/* $OpenBSD: rthread_debug.c,v 1.3 2017/09/05 02:40:54 guenther Exp $ */ + +/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman */ + +#include +#include +#include +#include + +#include "rthread.h" + +/* + * format and send output to stderr if the given "level" is less than or + * equal to the current debug level. Messages with a level <= 0 will + * always be printed. + */ +void +_rthread_debug(int level, const char *fmt, ...) +{ + if (_rthread_debug_level >= level) { + va_list ap; + va_start(ap, fmt); + vdprintf(STDERR_FILENO, fmt, ap); + va_end(ap); + } +} diff --git a/pthread/rthread_file.c b/pthread/rthread_file.c new file mode 100644 index 00000000..82d09684 --- /dev/null +++ b/pthread/rthread_file.c @@ -0,0 +1,305 @@ +/* $OpenBSD: rthread_file.c,v 1.2 2017/08/15 06:38:41 guenther Exp $ */ +/* + * Copyright (c) 1995 John Birrell . + * 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: uthread_file.c,v 1.9 1999/08/28 00:03:32 peter Exp $ + * + * POSIX stdio FILE locking functions. These assume that the locking + * is only required at FILE structure level, not at file descriptor + * level too. + * + */ + +#include +#include +#include +#include +#include + +#include "rthread.h" +#include "rthread_cb.h" + +/* + * The FILE lock structure. The FILE *fp is locked if the owner is + * not NULL. If not locked, the file lock structure can be + * reassigned to a different file by setting fp. + */ +struct file_lock { + LIST_ENTRY(file_lock) entry; /* Entry if file list. */ + FILE *fp; /* The target file. */ + struct pthread_queue lockers; + pthread_t owner; + int count; +}; + +/* + * The number of file lock lists into which the file pointer is + * hashed. Ideally, the FILE structure size would have been increased, + * but this causes incompatibility, so separate data structures are + * required. + */ +#define NUM_HEADS 128 + +/* + * This macro casts a file pointer to a long integer and right + * shifts this by the number of bytes in a pointer. The shifted + * value is then remaindered using the maximum number of hash + * entries to produce and index into the array of static lock + * structures. If there is a collision, a linear search of the + * dynamic list of locks linked to each static lock is perfomed. + */ +#define file_idx(_p) ((int)((((uintptr_t) _p) >> sizeof(void *)) % NUM_HEADS)) + +/* + * Global array of file locks. The first lock for each hash bucket is + * allocated statically in the hope that there won't be too many + * collisions that require a malloc and an element added to the list. + */ +static struct static_file_lock { + LIST_HEAD(file_list_head, file_lock) head; + struct file_lock fl; +} flh[NUM_HEADS]; + +/* Lock for accesses to the hash table: */ +static _atomic_lock_t hash_lock = _SPINLOCK_UNLOCKED; + +/* + * Find a lock structure for a FILE, return NULL if the file is + * not locked: + */ +static +struct file_lock * +find_lock(int idx, FILE *fp) +{ + struct file_lock *p; + + /* Check if the file is locked using the static structure: */ + if (flh[idx].fl.fp == fp && flh[idx].fl.owner != NULL) + /* Return a pointer to the static lock: */ + p = &flh[idx].fl; + else { + /* Point to the first dynamic lock: */ + p = LIST_FIRST(&flh[idx].head); + + /* + * Loop through the dynamic locks looking for the + * target file: + */ + while (p != NULL && (p->fp != fp || p->owner == NULL)) + /* Not this file, try the next: */ + p = LIST_NEXT(p, entry); + } + return(p); +} + +/* + * Lock a file, assuming that there is no lock structure currently + * assigned to it. + */ +static +struct file_lock * +do_lock(int idx, FILE *fp) +{ + struct file_lock *p; + + /* Check if the static structure is not being used: */ + if (flh[idx].fl.owner == NULL) { + /* Return a pointer to the static lock: */ + p = &flh[idx].fl; + } + else { + /* Point to the first dynamic lock: */ + p = LIST_FIRST(&flh[idx].head); + + /* + * Loop through the dynamic locks looking for a + * lock structure that is not being used: + */ + while (p != NULL && p->owner != NULL) + /* This one is used, try the next: */ + p = LIST_NEXT(p, entry); + } + + /* + * If an existing lock structure has not been found, + * allocate memory for a new one: + */ + if (p == NULL && (p = (struct file_lock *) + malloc(sizeof(struct file_lock))) != NULL) { + /* Add the new element to the list: */ + LIST_INSERT_HEAD(&flh[idx].head, p, entry); + } + + /* Check if there is a lock structure to acquire: */ + if (p != NULL) { + /* Acquire the lock for the running thread: */ + p->fp = fp; + p->owner = pthread_self(); + p->count = 1; + TAILQ_INIT(&p->lockers); + } + return(p); +} + +void +_thread_flockfile(FILE * fp) +{ + int idx = file_idx(fp); + struct file_lock *p; + pthread_t self = pthread_self(); + + /* Lock the hash table: */ + _spinlock(&hash_lock); + + /* Get a pointer to any existing lock for the file: */ + if ((p = find_lock(idx, fp)) == NULL) { + /* + * The file is not locked, so this thread can + * grab the lock: + */ + do_lock(idx, fp); + + /* + * The file is already locked, so check if the + * running thread is the owner: + */ + } else if (p->owner == self) { + /* + * The running thread is already the + * owner, so increment the count of + * the number of times it has locked + * the file: + */ + p->count++; + } else { + /* + * The file is locked for another thread. + * Append this thread to the queue of + * threads waiting on the lock. + */ + TAILQ_INSERT_TAIL(&p->lockers,self,waiting); + while (p->owner != self) { + __thrsleep(self, 0, NULL, &hash_lock, NULL); + _spinlock(&hash_lock); + } + } + + /* Unlock the hash table: */ + _spinunlock(&hash_lock); +} + +int +_thread_ftrylockfile(FILE * fp) +{ + int ret = -1; + int idx = file_idx(fp); + struct file_lock *p; + + /* Lock the hash table: */ + _spinlock(&hash_lock); + + /* Get a pointer to any existing lock for the file: */ + if ((p = find_lock(idx, fp)) == NULL) { + /* + * The file is not locked, so this thread can + * grab the lock: + */ + p = do_lock(idx, fp); + + /* + * The file is already locked, so check if the + * running thread is the owner: + */ + } else if (p->owner == pthread_self()) { + /* + * The running thread is already the + * owner, so increment the count of + * the number of times it has locked + * the file: + */ + p->count++; + } else { + /* + * The file is locked for another thread, + * so this try fails. + */ + p = NULL; + } + + /* Unlock the hash table: */ + _spinunlock(&hash_lock); + + /* Check if the lock was obtained: */ + if (p != NULL) + /* Return success: */ + ret = 0; + + return (ret); +} + +void +_thread_funlockfile(FILE * fp) +{ + int idx = file_idx(fp); + struct file_lock *p; + + /* Lock the hash table: */ + _spinlock(&hash_lock); + + /* + * Get a pointer to the lock for the file and check that + * the running thread is the one with the lock: + */ + if ((p = find_lock(idx, fp)) != NULL && p->owner == pthread_self()) { + /* + * Check if this thread has locked the FILE + * more than once: + */ + if (--p->count == 0) { + /* Get the new owner of the lock: */ + if ((p->owner = TAILQ_FIRST(&p->lockers)) != NULL) { + /* Pop the thread off the queue: */ + TAILQ_REMOVE(&p->lockers,p->owner,waiting); + + /* + * This is the first lock for the new + * owner: + */ + p->count = 1; + + __thrwakeup(p->owner, 1); + } + } + } + + /* Unlock the hash table: */ + _spinunlock(&hash_lock); +} diff --git a/pthread/rthread_getcpuclockid.c b/pthread/rthread_getcpuclockid.c new file mode 100644 index 00000000..ae42055f --- /dev/null +++ b/pthread/rthread_getcpuclockid.c @@ -0,0 +1,32 @@ +/* $OpenBSD: rthread_getcpuclockid.c,v 1.2 2016/05/07 19:05:22 guenther Exp $ */ +/* + * Copyright (c) 2013 Philip Guenther + * + * 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. + */ + +#include +#include + +#include "rthread.h" +#include "errno.h" + +int +pthread_getcpuclockid(pthread_t thread, clockid_t *clock_id) +{ + // TODO: + return (ENOSYS); + /**clock_id = __CLOCK_ENCODE(CLOCK_THREAD_CPUTIME_ID, + thread->tib->tib_tid); + return (0);*/ +} diff --git a/pthread/rthread_internal.c b/pthread/rthread_internal.c new file mode 100644 index 00000000..b4b727df --- /dev/null +++ b/pthread/rthread_internal.c @@ -0,0 +1,177 @@ +/* $OpenBSD: rthread.c,v 1.6 2017/11/04 22:53:57 jca Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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 infrastructure of rthreads + */ + +#include +#include +#include +#include +#include + +#include "phal.h" + +#include "rthread.h" + +#define RTHREAD_ENV_DEBUG "RTHREAD_DEBUG" + +int _rthread_debug_level; + +static int _threads_inited; + +struct pthread _initial_thread = { + .flags_lock = _SPINLOCK_UNLOCKED, + .name = "Original thread", +}; + +/* + * internal support functions + */ + +/* + * Atomic lock for arm + */ + +int +_atomic_lock(volatile _atomic_lock_t *lock) +{ + _atomic_lock_t old = 0; + uint32_t scratch = 0; + + __asm__("1: ldaxr %w0, [%x1] \n" + " stlxr %w2, %w3, [%x1] \n" + " cmp %w2, #0 \n" + " bne 1b \n" + " dmb sy \n" + : "+r" (old), "+r" (lock), "+r" (scratch) + : "r" (_ATOMIC_LOCK_LOCKED)); + + return (old != _ATOMIC_LOCK_UNLOCKED); +} + +void +_spinlock(volatile _atomic_lock_t *lock) +{ + while (_atomic_lock(lock)) + sched_yield(); +} + +int +_spinlocktry(volatile _atomic_lock_t *lock) +{ + return 0 == _atomic_lock(lock); +} + +void +_spinunlock(volatile _atomic_lock_t *lock) +{ + *lock = _ATOMIC_LOCK_UNLOCKED; +} + +void +_rthread_internal_init(phal_tid maintid) +{ + pthread_t thread = &_initial_thread; + //struct tib *tib; + + if (_threads_inited) + return; + + thread->tib_tid = maintid; + *phal_get_tls() = thread; + + //thread->donesem.lock = _SPINLOCK_UNLOCKED; + + thread->tib_thread_flags = TIB_THREAD_INITIAL_STACK; + + /* + * Set the debug level from an environment string. + * Bogus values are silently ignored. + */ + // TODO: issetugid + //if (! issetugid()) { + char *envp = getenv(RTHREAD_ENV_DEBUG); + + if (envp != NULL) { + char *rem; + + _rthread_debug_level = (int) strtol(envp, &rem, 0); + if (*rem != '\0' || _rthread_debug_level < 0) + _rthread_debug_level = 0; + } + //} + + _threads_inited = 1; +} + +/* + * real pthread functions + */ +pthread_t +pthread_self(void) +{ + if (__predict_false(!_threads_inited)) { + char msg[] = "_rthread_internal_init not called"; + write(2, msg, strlen(msg)); + return NULL; + } + + return *phal_get_tls(); +} + +void +pthread_exit(void *retval) +{ + struct rthread_cleanup_fn *clfn; + pthread_t thread = pthread_self(); + + if (thread->tib_cantcancel & CANCEL_DYING) { + /* + * Called pthread_exit() from destructor or cancelation + * handler: blow up. XXX write something to stderr? + */ + abort(); + //_exit(42); + } + + thread->tib_cantcancel |= CANCEL_DYING; + + thread->retval = retval; + + for (clfn = thread->cleanup_fns; clfn; ) { + struct rthread_cleanup_fn *oclfn = clfn; + clfn = clfn->next; + oclfn->fn(oclfn->arg); + free(oclfn); + } + _rthread_tls_destructors(thread); + _rthread_release(thread); + + phal_thread_exit(&thread->tib_tid); + + // We should never reach here. + for(;;); +} + +int +pthread_equal(pthread_t t1, pthread_t t2) +{ + return (t1 == t2); +} + diff --git a/pthread/rthread_libc.c b/pthread/rthread_libc.c new file mode 100644 index 00000000..b3fcf22c --- /dev/null +++ b/pthread/rthread_libc.c @@ -0,0 +1,283 @@ +/* $OpenBSD: rthread_libc.c,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ + +/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman */ + +#include +#include +#include + +#include "rthread.h" +#include "rthread_cb.h" + +/* + * A thread tag is a pointer to a structure of this type. An opaque + * tag is used to decouple libc from the thread library. + */ +struct _thread_tag { + pthread_mutex_t m; /* the tag's mutex */ + pthread_key_t k; /* a key for private data */ +}; + +/* + * local mutex to protect against tag creation races. + */ +static pthread_mutex_t _thread_tag_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * Initialize a thread tag structure once. This function is called + * if the tag is null. Allocation and initialization are controlled + * by a mutex. If the tag is not null when the mutex is obtained + * the caller lost a race -- some other thread initialized the tag. + * This function will never return NULL. + */ +static void +_thread_tag_init(void **tag) +{ + struct _thread_tag *tt; + int result; + + result = pthread_mutex_lock(&_thread_tag_mutex); + if (result == 0) { + if (*tag == NULL) { + tt = malloc(sizeof *tt); + if (tt != NULL) { + result = pthread_mutex_init(&tt->m, NULL); + result |= pthread_key_create(&tt->k, free); + *tag = tt; + } + } + result |= pthread_mutex_unlock(&_thread_tag_mutex); + } + if (result != 0) + _rthread_debug(1, "tag init failure"); +} + +/* + * lock the mutex associated with the given tag + */ +void +_thread_tag_lock(void **tag) +{ + struct _thread_tag *tt; + + if (__isthreaded) { + if (*tag == NULL) + _thread_tag_init(tag); + tt = *tag; + if (pthread_mutex_lock(&tt->m) != 0) + _rthread_debug(1, "tag mutex lock failure"); + } +} + +/* + * unlock the mutex associated with the given tag + */ +void +_thread_tag_unlock(void **tag) +{ + struct _thread_tag *tt; + + if (__isthreaded) { + if (*tag == NULL) + _thread_tag_init(tag); + tt = *tag; + if (pthread_mutex_unlock(&tt->m) != 0) + _rthread_debug(1, "tag mutex unlock failure"); + } +} + +/* + * return the thread specific data for the given tag. If there + * is no data for this thread initialize it from 'storage'. + * On any error return 'err'. + */ +void * +_thread_tag_storage(void **tag, void *storage, size_t sz, void *err) +{ + struct _thread_tag *tt; + void *ret; + + if (*tag == NULL) + _thread_tag_init(tag); + tt = *tag; + + ret = pthread_getspecific(tt->k); + if (ret == NULL) { + ret = malloc(sz); + if (ret == NULL) + ret = err; + else { + if (pthread_setspecific(tt->k, ret) == 0) + memcpy(ret, storage, sz); + else { + free(ret); + ret = err; + } + } + } + return ret; +} + +void +_thread_mutex_lock(void **mutex) +{ + pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; + + if (pthread_mutex_lock(pmutex) != 0) + _rthread_debug(1, "mutex lock failure"); +} + +void +_thread_mutex_unlock(void **mutex) +{ + pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; + + if (pthread_mutex_unlock(pmutex) != 0) + _rthread_debug(1, "mutex unlock failure"); +} + +void +_thread_mutex_destroy(void **mutex) +{ + pthread_mutex_t *pmutex = (pthread_mutex_t *)mutex; + + if (pthread_mutex_destroy(pmutex) != 0) + _rthread_debug(1, "mutex destroy failure"); +} + +/* + * the malloc lock + */ +#ifndef FUTEX +#define MALLOC_LOCK_INITIALIZER(n) { \ + _SPINLOCK_UNLOCKED, \ + TAILQ_HEAD_INITIALIZER(malloc_lock[n].lockers), \ + PTHREAD_MUTEX_DEFAULT, \ + NULL, \ + 0, \ + -1 } +#else +#define MALLOC_LOCK_INITIALIZER(n) { \ + _SPINLOCK_UNLOCKED, \ + PTHREAD_MUTEX_DEFAULT, \ + NULL, \ + 0, \ + -1 } +#endif + +static struct pthread_mutex malloc_lock[_MALLOC_MUTEXES] = { + MALLOC_LOCK_INITIALIZER(0), + MALLOC_LOCK_INITIALIZER(1), + MALLOC_LOCK_INITIALIZER(2), + MALLOC_LOCK_INITIALIZER(3) +}; + +static pthread_mutex_t malloc_mutex[_MALLOC_MUTEXES] = { + &malloc_lock[0], + &malloc_lock[1], + &malloc_lock[2], + &malloc_lock[3] +}; + +void +_thread_malloc_lock(int i) +{ + pthread_mutex_lock(&malloc_mutex[i]); +} + +void +_thread_malloc_unlock(int i) +{ + pthread_mutex_unlock(&malloc_mutex[i]); +} + +static void +_thread_malloc_reinit(void) +{ + int i; + + for (i = 0; i < _MALLOC_MUTEXES; i++) { + malloc_lock[i].lock = _SPINLOCK_UNLOCKED; +#ifndef FUTEX + TAILQ_INIT(&malloc_lock[i].lockers); +#endif + malloc_lock[i].owner = NULL; + malloc_lock[i].count = 0; + } +} + +/* + * atexit lock + */ +static _atomic_lock_t atexit_lock = _SPINLOCK_UNLOCKED; + +void +_thread_atexit_lock(void) +{ + _spinlock(&atexit_lock); +} + +void +_thread_atexit_unlock(void) +{ + _spinunlock(&atexit_lock); +} + +/* + * atfork lock + */ +static _atomic_lock_t atfork_lock = _SPINLOCK_UNLOCKED; + +void +_thread_atfork_lock(void) +{ + _spinlock(&atfork_lock); +} + +void +_thread_atfork_unlock(void) +{ + _spinunlock(&atfork_lock); +} + +/* + * arc4random lock + */ +static _atomic_lock_t arc4_lock = _SPINLOCK_UNLOCKED; + +void +_thread_arc4_lock(void) +{ + _spinlock(&arc4_lock); +} + +void +_thread_arc4_unlock(void) +{ + _spinunlock(&arc4_lock); +} + +pid_t +_thread_dofork(pid_t (*sys_fork)(void)) +{ + int i; + pid_t newid; + + _thread_atexit_lock(); + for (i = 0; i < _MALLOC_MUTEXES; i++) + _thread_malloc_lock(i); + _thread_arc4_lock(); + + newid = sys_fork(); + + _thread_arc4_unlock(); + if (newid == 0) + _thread_malloc_reinit(); + else + for (i = 0; i < _MALLOC_MUTEXES; i++) + _thread_malloc_unlock(i); + _thread_atexit_unlock(); + + return newid; +} + diff --git a/pthread/rthread_mutex.c b/pthread/rthread_mutex.c new file mode 100644 index 00000000..dc0d731c --- /dev/null +++ b/pthread/rthread_mutex.c @@ -0,0 +1,297 @@ +/* $OpenBSD: rthread_mutex.c,v 1.3 2017/08/15 07:06:29 guenther Exp $ */ +/* + * Copyright (c) 2017 Martin Pieuchot + * Copyright (c) 2012 Philip Guenther + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rthread.h" +#include "synch.h" + +/* + * States defined in "Futexes Are Tricky" 5.2 + */ +enum { + UNLOCKED = 0, + LOCKED = 1, /* locked without waiter */ + CONTENDED = 2, /* threads waiting for this mutex */ +}; + +#define SPIN_COUNT 128 +#if defined(__i386__) || defined(__amd64__) +#define SPIN_WAIT() asm volatile("pause": : : "memory") +#else +#define SPIN_WAIT() do { } while (0) +#endif + +static _atomic_lock_t static_init_lock = _SPINLOCK_UNLOCKED; + +int +pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr) +{ + pthread_mutex_t mutex; + + mutex = calloc(1, sizeof(*mutex)); + if (mutex == NULL) + return (ENOMEM); + + //phal_mutex_init(&mutex->hal_handle); + if (attr == NULL) { + mutex->type = PTHREAD_MUTEX_DEFAULT; + mutex->prioceiling = -1; + } else { + mutex->type = (*attr)->ma_type; + mutex->prioceiling = (*attr)->ma_protocol == + PTHREAD_PRIO_PROTECT ? (*attr)->ma_prioceiling : -1; + } + *mutexp = mutex; + + return (0); +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutexp) +{ + pthread_mutex_t mutex; + + if (mutexp == NULL || *mutexp == NULL) + return (EINVAL); + + mutex = *mutexp; + if (mutex) { + if (mutex->lock != UNLOCKED) { +#define MSG "pthread_mutex_destroy on mutex with waiters!\n" + write(2, MSG, sizeof(MSG) - 1); +#undef MSG + return (EBUSY); + } + free((void *)mutex); + *mutexp = NULL; + } + + return (0); +} + +static int +_rthread_mutex_trylock(pthread_mutex_t mutex, int trywait, + const struct timespec *abs) +{ + pthread_t self = pthread_self(); + int unlocked = UNLOCKED; + if (atomic_compare_exchange_strong(&mutex->lock, &unlocked, LOCKED)) { + // TODO: Membar + //membar_enter_after_atomic(); + mutex->owner = self; + return (0); + } + + if (mutex->owner == self) { + int type = mutex->type; + + /* already owner? handle recursive behavior */ + if (type != PTHREAD_MUTEX_RECURSIVE) { + if (trywait || type == PTHREAD_MUTEX_ERRORCHECK) + return (trywait ? EBUSY : EDEADLK); + + /* self-deadlock is disallowed by strict */ + if (type == PTHREAD_MUTEX_STRICT_NP && abs == NULL) + abort(); + + /* self-deadlock, possibly until timeout */ + phal_semaphore_lock(&mutex->sem); + phal_semaphore_wait(&mutex->sem, abs); + phal_semaphore_unlock(&mutex->sem); + return (ETIMEDOUT); + } else { + if (mutex->count == INT_MAX) + return (EAGAIN); + mutex->count++; + return (0); + } + } + + return (EBUSY); +} + +static int +_rthread_mutex_timedlock(pthread_mutex_t *mutexp, int trywait, + const struct timespec *abs, int timed) +{ + pthread_t self = pthread_self(); + pthread_mutex_t mutex; + unsigned int i; + int lock, error = 0; + + if (mutexp == NULL) + return (EINVAL); + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization. Note: _thread_mutex_lock() in libc requires + * pthread_mutex_lock() to perform the mutex init when *mutexp + * is NULL. + */ + if (*mutexp == NULL) { + _spinlock(&static_init_lock); + if (*mutexp == NULL) + error = pthread_mutex_init(mutexp, NULL); + _spinunlock(&static_init_lock); + if (error != 0) + return (EINVAL); + } + + mutex = *mutexp; + _rthread_debug(5, "%p: mutex_%slock %p (%p)\n", self, + (timed ? "timed" : (trywait ? "try" : "")), (void *)mutex, + (void *)mutex->owner); + + error = _rthread_mutex_trylock(mutex, trywait, abs); + if (error != EBUSY || trywait) + return (error); + + /* Try hard to not enter the kernel. */ + for (i = 0; i < SPIN_COUNT; i ++) { + if (mutex->lock == UNLOCKED) + break; + + SPIN_WAIT(); + } + + lock = UNLOCKED; + atomic_compare_exchange_strong(&mutex->lock, &lock, LOCKED); + if (lock == UNLOCKED) { + // TODO: membar + //membar_enter_after_atomic(); + mutex->owner = self; + return (0); + } + + if (lock != CONTENDED) { + /* Indicate that we're waiting on this mutex. */ + lock = atomic_exchange(&mutex->lock, CONTENDED); + } + + while (lock != UNLOCKED) { + // We don't *actually* need the lock here, as we are only using this to + // allow cross-thread signaling. + // If I could remove the mutex, I would, but I think switch's + // implementation actually requires a valid, locked mutex. + // TODO: error handling. + phal_semaphore_lock(&mutex->sem); + error = phal_semaphore_wait(&mutex->sem, abs); + phal_semaphore_unlock(&mutex->sem); + if (error == ETIMEDOUT) + return (error); + /* + * We cannot know if there's another waiter, so in + * doubt set the state to CONTENDED. + */ + lock = atomic_exchange(&mutex->lock, CONTENDED); + }; + + // TODO: membar + //membar_enter_after_atomic(); + mutex->owner = self; + return (0); +} + +int +pthread_mutex_trylock(pthread_mutex_t *mutexp) +{ + return (_rthread_mutex_timedlock(mutexp, 1, NULL, 0)); +} + +int +pthread_mutex_timedlock(pthread_mutex_t *mutexp, const struct timespec *abs) +{ + return (_rthread_mutex_timedlock(mutexp, 0, abs, 1)); +} + +int +pthread_mutex_lock(pthread_mutex_t *mutexp) +{ + return (_rthread_mutex_timedlock(mutexp, 0, NULL, 0)); +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutexp) +{ + pthread_t self = pthread_self(); + pthread_mutex_t mutex; + + if (mutexp == NULL) + return (EINVAL); + + if (*mutexp == NULL) +#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK + return (EPERM); +#elif PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + return(0); +#else + abort(); +#endif + + mutex = *mutexp; + _rthread_debug(5, "%p: mutex_unlock %p (%p)\n", self, (void *)mutex, + (void *)mutex->owner); + + if (mutex->owner != self) { + _rthread_debug(5, "%p: different owner %p (%p)\n", self, (void *)mutex, + (void *)mutex->owner); + if (mutex->type == PTHREAD_MUTEX_ERRORCHECK || + mutex->type == PTHREAD_MUTEX_RECURSIVE) { + return (EPERM); + } else { + /* + * For mutex type NORMAL our undefined behavior for + * unlocking an unlocked mutex is to succeed without + * error. All other undefined behaviors are to + * abort() immediately. + */ + if (mutex->owner == NULL && + mutex->type == PTHREAD_MUTEX_NORMAL) + return (0); + else + abort(); + + } + } + + if (mutex->type == PTHREAD_MUTEX_RECURSIVE) { + if (mutex->count > 0) { + mutex->count--; + return (0); + } + } + + mutex->owner = NULL; + // TODO: membar + //membar_exit_before_atomic(); + if (atomic_fetch_sub(&mutex->lock, 1) != (UNLOCKED + 1)) { + mutex->lock = UNLOCKED; + phal_semaphore_lock(&mutex->sem); + phal_semaphore_signal(&mutex->sem); + phal_semaphore_unlock(&mutex->sem); + } + + return (0); +} diff --git a/pthread/rthread_mutex_prio.c b/pthread/rthread_mutex_prio.c new file mode 100644 index 00000000..d675b37e --- /dev/null +++ b/pthread/rthread_mutex_prio.c @@ -0,0 +1,54 @@ +/* $OpenBSD: rthread_mutex_prio.c,v 1.2 2014/06/23 00:43:15 guenther Exp $ */ +/* + * Copyright (c) 2011 Philip Guenther + * + * 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. + */ + + +#include + +#include +#include "rthread.h" + +int +pthread_mutex_getprioceiling(pthread_mutex_t *mutexp, int *prioceiling) +{ + pthread_mutex_t mutex = *mutexp; + + if (mutex->prioceiling == -1) + return (EINVAL); + *prioceiling = mutex->prioceiling; + + return (0); +} + +int +pthread_mutex_setprioceiling(pthread_mutex_t *mutexp, int prioceiling, + int *old_ceiling) +{ + pthread_mutex_t mutex = *mutexp; + int ret; + + if (mutex->prioceiling == -1 || + prioceiling < PTHREAD_MIN_PRIORITY || + prioceiling > PTHREAD_MAX_PRIORITY) { + ret = EINVAL; + } else if ((ret = pthread_mutex_lock(mutexp)) == 0) { + *old_ceiling = mutex->prioceiling; + mutex->prioceiling = prioceiling; + pthread_mutex_unlock(mutexp); + } + + return (ret); +} diff --git a/pthread/rthread_mutexattr.c b/pthread/rthread_mutexattr.c new file mode 100644 index 00000000..0c4fc0ed --- /dev/null +++ b/pthread/rthread_mutexattr.c @@ -0,0 +1,131 @@ +/* $OpenBSD: rthread_mutexattr.c,v 1.3 2012/04/13 13:50:37 kurt Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * Copyright (c) 2011 Philip Guenther + * 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. + */ +/* + * Mutex attributes + */ + + +#include +#include +#include + +#include + +#include "rthread.h" + +int +pthread_mutexattr_init(pthread_mutexattr_t *attrp) +{ + pthread_mutexattr_t attr; + + attr = calloc(1, sizeof(*attr)); + if (!attr) + return (errno); + attr->ma_type = PTHREAD_MUTEX_DEFAULT; + *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) +{ + if (type < PTHREAD_MUTEX_ERRORCHECK || type >= PTHREAD_MUTEX_TYPE_MAX) + return (EINVAL); + (*attrp)->ma_type = type; + return (0); +} + +int +pthread_mutexattr_gettype(pthread_mutexattr_t *attrp, int *type) +{ + *type = (*attrp)->ma_type; + return (0); +} + +int +pthread_mutexattr_setprotocol(pthread_mutexattr_t *attrp, int protocol) +{ + if (protocol < PTHREAD_PRIO_NONE || protocol > PTHREAD_PRIO_PROTECT) + return (EINVAL); + (*attrp)->ma_protocol = protocol; + return (0); +} + +int +pthread_mutexattr_getprotocol(pthread_mutexattr_t *attrp, int *protocol) +{ + *protocol = (*attrp)->ma_protocol; + return (0); +} + +int +pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attrp, int prioceiling) +{ + if (prioceiling < PTHREAD_MIN_PRIORITY || + prioceiling > PTHREAD_MAX_PRIORITY) + return (EINVAL); + (*attrp)->ma_prioceiling = prioceiling; + return (0); +} + +int +pthread_mutexattr_getprioceiling(pthread_mutexattr_t *attrp, int *prioceiling) +{ + *prioceiling = (*attrp)->ma_prioceiling; + return (0); +} + +int +pthread_mutexattr_getkind_np(pthread_mutexattr_t attrp) +{ + int ret; + + if (attrp == NULL) + ret = EINVAL; + else + ret = attrp->ma_type; + + return(ret); +} + +int +pthread_mutexattr_setkind_np(pthread_mutexattr_t *attrp, int kind) +{ + int ret; + + if (attrp == NULL || *attrp == NULL || + kind < PTHREAD_MUTEX_ERRORCHECK || kind >= PTHREAD_MUTEX_TYPE_MAX) + ret = EINVAL; + else { + (*attrp)->ma_type = kind; + ret = 0; + } + + return (ret); +} diff --git a/pthread/rthread_once.c b/pthread/rthread_once.c new file mode 100644 index 00000000..a9b6749d --- /dev/null +++ b/pthread/rthread_once.c @@ -0,0 +1,32 @@ +/* $OpenBSD: rthread_once.c,v 1.3 2017/11/04 22:53:57 jca Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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. + */ + +#include + +int +pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + pthread_mutex_lock(&once_control->mutex); + if (once_control->state == PTHREAD_NEEDS_INIT) { + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + } + pthread_mutex_unlock(&once_control->mutex); + + return (0); +} diff --git a/pthread/rthread_rwlock.c b/pthread/rthread_rwlock.c new file mode 100644 index 00000000..2cc4f01b --- /dev/null +++ b/pthread/rthread_rwlock.c @@ -0,0 +1,266 @@ +/* $OpenBSD: rthread_rwlock.c,v 1.10 2017/07/29 16:42:10 deraadt Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * Copyright (c) 2012 Philip Guenther + * 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. + */ +/* + * rwlocks + */ + +#include +#include +#include +#include + +#include + +#include "rthread.h" + +static _atomic_lock_t rwlock_init_lock = _SPINLOCK_UNLOCKED; + +int +pthread_rwlock_init(pthread_rwlock_t *lockp, + const pthread_rwlockattr_t *attrp __unused) +{ + pthread_rwlock_t lock; + + lock = calloc(1, sizeof(*lock)); + if (!lock) + return (errno); + lock->lock = _SPINLOCK_UNLOCKED; + TAILQ_INIT(&lock->writers); + + *lockp = lock; + + return (0); +} + +int +pthread_rwlock_destroy(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + assert(lockp); + lock = *lockp; + if (lock) { + if (lock->readers || !TAILQ_EMPTY(&lock->writers)) { +#define MSG "pthread_rwlock_destroy on rwlock with waiters!\n" + write(2, MSG, sizeof(MSG) - 1); +#undef MSG + return (EBUSY); + } + free(lock); + } + *lockp = NULL; + + return (0); +} + +static int +_rthread_rwlock_ensure_init(pthread_rwlock_t *lockp) +{ + int ret = 0; + + /* + * If the rwlock is statically initialized, perform the dynamic + * initialization. + */ + if (*lockp == NULL) + { + _spinlock(&rwlock_init_lock); + if (*lockp == NULL) + ret = pthread_rwlock_init(lockp, NULL); + _spinunlock(&rwlock_init_lock); + } + return (ret); +} + + +static int +_rthread_rwlock_rdlock(pthread_rwlock_t *lockp, const struct timespec *abstime, + int try) +{ + pthread_rwlock_t lock; + pthread_t thread = pthread_self(); + int error; + + if ((error = _rthread_rwlock_ensure_init(lockp))) + return (error); + + lock = *lockp; + _rthread_debug(5, "%p: rwlock_rdlock %p\n", (void *)thread, + (void *)lock); + _spinlock(&lock->lock); + + /* writers have precedence */ + if (lock->owner == NULL && TAILQ_EMPTY(&lock->writers)) + lock->readers++; + else if (try) + error = EBUSY; + else if (lock->owner == thread) + error = EDEADLK; + else { + do { + // TODO: Sleep + /*if (__thrsleep(lock, CLOCK_REALTIME, abstime, + &lock->lock, NULL) == EWOULDBLOCK) + return (ETIMEDOUT);*/ + _spinlock(&lock->lock); + } while (lock->owner != NULL || !TAILQ_EMPTY(&lock->writers)); + lock->readers++; + } + _spinunlock(&lock->lock); + + return (error); +} + +int +pthread_rwlock_rdlock(pthread_rwlock_t *lockp) +{ + return (_rthread_rwlock_rdlock(lockp, NULL, 0)); +} + +int +pthread_rwlock_tryrdlock(pthread_rwlock_t *lockp) +{ + return (_rthread_rwlock_rdlock(lockp, NULL, 1)); +} + +int +pthread_rwlock_timedrdlock(pthread_rwlock_t *lockp, + const struct timespec *abstime) +{ + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec > 1000000000) + return (EINVAL); + return (_rthread_rwlock_rdlock(lockp, abstime, 0)); +} + + +static int +_rthread_rwlock_wrlock(pthread_rwlock_t *lockp, const struct timespec *abstime, + int try) +{ + pthread_rwlock_t lock; + pthread_t thread = pthread_self(); + int error; + + if ((error = _rthread_rwlock_ensure_init(lockp))) + return (error); + + lock = *lockp; + + _rthread_debug(5, "%p: rwlock_timedwrlock %p\n", (void *)thread, + (void *)lock); + _spinlock(&lock->lock); + if (lock->readers == 0 && lock->owner == NULL) + lock->owner = thread; + else if (try) + error = EBUSY; + else if (lock->owner == thread) + error = EDEADLK; + else { + int do_wait; + + /* gotta block */ + TAILQ_INSERT_TAIL(&lock->writers, thread, waiting); + do { + return ENOSYS; + // TODO: __thrsleep + /*do_wait = __thrsleep(thread, CLOCK_REALTIME, abstime, + &lock->lock, NULL) != EWOULDBLOCK;*/ + _spinlock(&lock->lock); + } while (lock->owner != thread && do_wait); + + if (lock->owner != thread) { + /* timed out, sigh */ + TAILQ_REMOVE(&lock->writers, thread, waiting); + error = ETIMEDOUT; + } + } + _spinunlock(&lock->lock); + + return (error); +} + +int +pthread_rwlock_wrlock(pthread_rwlock_t *lockp) +{ + return (_rthread_rwlock_wrlock(lockp, NULL, 0)); +} + +int +pthread_rwlock_trywrlock(pthread_rwlock_t *lockp) +{ + return (_rthread_rwlock_wrlock(lockp, NULL, 1)); +} + +int +pthread_rwlock_timedwrlock(pthread_rwlock_t *lockp, + const struct timespec *abstime) +{ + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec > 1000000000) + return (EINVAL); + return (_rthread_rwlock_wrlock(lockp, abstime, 0)); +} + + +int +pthread_rwlock_unlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + pthread_t thread = pthread_self(); + pthread_t next; + int was_writer; + + lock = *lockp; + + _rthread_debug(5, "%p: rwlock_unlock %p\n", (void *)thread, + (void *)lock); + _spinlock(&lock->lock); + if (lock->owner != NULL) { + assert(lock->owner == thread); + was_writer = 1; + } else { + assert(lock->readers > 0); + lock->readers--; + if (lock->readers > 0) + goto out; + was_writer = 0; + } + + lock->owner = next = TAILQ_FIRST(&lock->writers); + if (next != NULL) { + /* dequeue and wake first writer */ + TAILQ_REMOVE(&lock->writers, next, waiting); + _spinunlock(&lock->lock); + return ENOSYS; + // TODO: thrwakeup + //__thrwakeup(next, 1); + return (0); + } + + /* could there have been blocked readers? wake them all */ + if (was_writer) + return ENOSYS; + // TODO: __thrwakeup + //__thrwakeup(lock, 0); +out: + _spinunlock(&lock->lock); + + return (0); +} diff --git a/pthread/rthread_rwlockattr.c b/pthread/rthread_rwlockattr.c new file mode 100644 index 00000000..90209f1e --- /dev/null +++ b/pthread/rthread_rwlockattr.c @@ -0,0 +1,72 @@ +/* $OpenBSD: rthread_rwlockattr.c,v 1.2 2012/02/15 04:58:42 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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. + */ +/* + * rwlock attributes + */ + + +#include +#include +#include + +#include + +#include "rthread.h" + +int +pthread_rwlockattr_init(pthread_rwlockattr_t *attrp) +{ + pthread_rwlockattr_t attr; + + attr = calloc(1, sizeof(*attr)); + if (!attr) + return (errno); + attr->pshared = PTHREAD_PROCESS_PRIVATE; + *attrp = attr; + + return (0); +} + +int +pthread_rwlockattr_destroy(pthread_rwlockattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +int +pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attrp, int *pshared) +{ + *pshared = (*attrp)->pshared; + + return (0); +} + +int +pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attrp, int pshared) +{ + /* only PTHREAD_PROCESS_PRIVATE is supported */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (EINVAL); + + (*attrp)->pshared = pshared; + + return (0); +} diff --git a/pthread/rthread_sched.c b/pthread/rthread_sched.c new file mode 100644 index 00000000..0b6692ee --- /dev/null +++ b/pthread/rthread_sched.c @@ -0,0 +1,146 @@ +/* $OpenBSD: rthread_sched.c,v 1.14 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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 +#include +#include + +#include + +#include "rthread.h" + +int +pthread_getschedparam(pthread_t thread, int *policy, + struct sched_param *param) +{ + if (!_threads_ready) + _rthread_init(); + + *policy = thread->attr.sched_policy; + if (param) + *param = thread->attr.sched_param; + + return (0); +} + +int +pthread_setschedparam(pthread_t thread, int policy, + const struct sched_param *param) +{ + if (!_threads_ready) + _rthread_init(); + + /* XXX return ENOTSUP for SCHED_{FIFO,RR}? */ + if (policy != SCHED_OTHER && policy != SCHED_FIFO && + policy != SCHED_RR) + return (EINVAL); + thread->attr.sched_policy = policy; + if (param) + thread->attr.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) +{ + /* XXX return ENOTSUP for SCHED_{FIFO,RR}? */ + if (policy != SCHED_OTHER && policy != SCHED_FIFO && + policy != SCHED_RR) + return (EINVAL); + (*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) +{ + if (inherit != PTHREAD_INHERIT_SCHED && + inherit != PTHREAD_EXPLICIT_SCHED) + return (EINVAL); + (*attrp)->sched_inherit = inherit; + + return (0); +} + +int +pthread_getprio(pthread_t thread) +{ + if (!_threads_ready) + _rthread_init(); + + return (thread->attr.sched_param.sched_priority); +} + +int +pthread_setprio(pthread_t thread, int priority) +{ + if (!_threads_ready) + _rthread_init(); + + thread->attr.sched_param.sched_priority = priority; + + return (0); +} + +void +pthread_yield(void) +{ + // TODO: sched_yield + return; + //sched_yield(); +} + diff --git a/pthread/rthread_sem.c b/pthread/rthread_sem.c new file mode 100644 index 00000000..77423319 --- /dev/null +++ b/pthread/rthread_sem.c @@ -0,0 +1,441 @@ +/* $OpenBSD: rthread_sem.c,v 1.26 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005,2013 Ted Unangst + * 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. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rthread.h" + +#define SHARED_IDENT ((void *)-1) + +/* SHA256_DIGEST_STRING_LENGTH includes nul */ +/* "/tmp/" + sha256 + ".sem" */ +#define SEM_PATH_SIZE (5 + SHA256_DIGEST_STRING_LENGTH + 4) + +/* long enough to be hard to guess */ +#define SEM_RANDOM_NAME_LEN 10 + +/* + * Size of memory to be mmap()'ed by named semaphores. + * Should be >= SEM_PATH_SIZE and page-aligned. + */ +#define SEM_MMAP_SIZE _thread_pagesize + +#define SEM_VALUE_MAX UINT_MAX + +/* + * Internal implementation of semaphores + */ +int +_sem_wait(sem_t sem, int tryonly, const struct timespec *abstime, + int *delayed_cancel) +{ + // This should never happen + int r; + + if (sem->shared) + return ENOSYS; + + phal_semaphore_lock(&sem->sem); + if (sem->value) { + sem->value--; + r = 0; + } else if (tryonly) { + r = EAGAIN; + } else { + sem->waitcount++; + do { + r = phal_semaphore_wait(&sem->sem, abstime); + // TODO: Delayed_cancel ? + // At this point, I already have lock ! But do I need it ? + //_spinlock(&sem->lock); + /* ignore interruptions other than cancelation */ + if (r == EINTR && (delayed_cancel == NULL || + *delayed_cancel == 0)) + r = 0; + } while (r == 0 && sem->value == 0); + sem->waitcount--; + if (r == 0) + sem->value--; + } + phal_semaphore_unlock(&sem->sem); + return (r); +} + +/* always increment count */ +int +_sem_post(sem_t sem) +{ + //void *ident = (void *)&sem->waitcount; + int rv = 0; + + if (sem->shared) + return ENOSYS; + + phal_semaphore_lock(&sem->sem); + sem->value++; + if (sem->waitcount) { + phal_semaphore_signal(&sem->sem); + // TODO: rv ? + rv = 1; + } + phal_semaphore_unlock(&sem->sem); + return (rv); +} + +/* + * exported semaphores + */ +int +sem_init(sem_t *semp, int pshared, unsigned int value) +{ + sem_t sem; + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return (-1); + } + + if (pshared) { + errno = EPERM; + return (-1); +#ifdef notyet + char name[SEM_RANDOM_NAME_LEN]; + sem_t *sempshared; + int i; + + for (;;) { + for (i = 0; i < SEM_RANDOM_NAME_LEN - 1; i++) + name[i] = arc4random_uniform(255) + 1; + name[SEM_RANDOM_NAME_LEN - 1] = '\0'; + sempshared = sem_open(name, O_CREAT | O_EXCL, 0, value); + if (sempshared != SEM_FAILED) + break; + if (errno == EEXIST) + continue; + if (errno != EPERM) + errno = ENOSPC; + return (-1); + } + + /* unnamed semaphore should not be opened twice */ + if (sem_unlink(name) == -1) { + sem_close(sempshared); + errno = ENOSPC; + return (-1); + } + + *semp = *sempshared; + free(sempshared); + return (0); +#endif + } + + sem = calloc(1, sizeof(*sem)); + if (!sem) { + errno = ENOSPC; + return (-1); + } + phal_semaphore_create(&sem->sem); + sem->value = value; + *semp = sem; + + return (0); +} + +int +sem_destroy(sem_t *semp) +{ + sem_t sem; + + if (!_threads_ready) /* for SEM_MMAP_SIZE */ + _rthread_init(); + + if (!semp || !(sem = *semp)) { + errno = EINVAL; + return (-1); + } + + if (sem->waitcount) { +#define MSG "sem_destroy on semaphore with waiters!\n" + write(2, MSG, sizeof(MSG) - 1); +#undef MSG + errno = EBUSY; + return (-1); + } + + *semp = NULL; + if (sem->shared) + return ENOSYS; + // TODO: munmap + //munmap(sem, SEM_MMAP_SIZE); + else + free(sem); + + return (0); +} + +int +sem_getvalue(sem_t *semp, int *sval) +{ + sem_t sem; + + if (!semp || !(sem = *semp)) { + errno = EINVAL; + return (-1); + } + + // TODO: Do I really need locking here ? I don't think so. + phal_semaphore_lock(&sem->sem); + *sval = sem->value; + phal_semaphore_unlock(&sem->sem); + + return (0); +} + +int +sem_post(sem_t *semp) +{ + sem_t sem; + + if (!semp || !(sem = *semp)) { + errno = EINVAL; + return (-1); + } + + _sem_post(sem); + + return (0); +} + +int +sem_wait(sem_t *semp) +{ + pthread_t self = pthread_self(); + sem_t sem; + int r; + //PREP_CANCEL_POINT(tib); + + if (!_threads_ready) + _rthread_init(); + + if (!semp || !(sem = *semp)) { + errno = EINVAL; + return (-1); + } + + //ENTER_DELAYED_CANCEL_POINT(tib, self); + r = _sem_wait(sem, 0, NULL, &self->delayed_cancel); + //LEAVE_CANCEL_POINT_INNER(tib, r); + + if (r) { + errno = r; + return (-1); + } + + return (0); +} + +int +sem_timedwait(sem_t *semp, const struct timespec *abstime) +{ + pthread_t self; + sem_t sem; + int r; + //PREP_CANCEL_POINT(tib); + + if (!_threads_ready) + _rthread_init(); + self = pthread_self(); + + if (!semp || !(sem = *semp)) { + errno = EINVAL; + return (-1); + } + + //ENTER_DELAYED_CANCEL_POINT(tib, self); + r = _sem_wait(sem, 0, abstime, &self->delayed_cancel); + //LEAVE_CANCEL_POINT_INNER(tib, r); + + if (r) { + errno = r == EWOULDBLOCK ? ETIMEDOUT : r; + return (-1); + } + + return (0); +} + +int +sem_trywait(sem_t *semp) +{ + sem_t sem; + int r; + + if (!semp || !(sem = *semp)) { + errno = EINVAL; + return (-1); + } + + r = _sem_wait(sem, 1, NULL, NULL); + + if (r) { + errno = r; + return (-1); + } + + return (0); +} + + +/*static void +makesempath(const char *origpath, char *sempath, size_t len) +{ + char buf[SHA256_DIGEST_STRING_LENGTH]; + + SHA256Data(origpath, strlen(origpath), buf); + snprintf(sempath, len, "/tmp/%s.sem", buf); +}*/ + +sem_t * +sem_open(const char *name, int oflag, ...) +{ + errno = ENOSYS; + return SEM_FAILED; +#if 0 + char sempath[SEM_PATH_SIZE]; + struct stat sb; + sem_t sem, *semp; + unsigned int value = 0; + int created = 0, fd; + + if (!_threads_ready) + _rthread_init(); + + if (oflag & ~(O_CREAT | O_EXCL)) { + errno = EINVAL; + return (SEM_FAILED); + } + + if (oflag & O_CREAT) { + va_list ap; + va_start(ap, oflag); + /* 3rd parameter mode is not used */ + va_arg(ap, mode_t); + value = va_arg(ap, unsigned); + va_end(ap); + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return (SEM_FAILED); + } + } + + makesempath(name, sempath, sizeof(sempath)); + fd = open(sempath, O_RDWR | O_NOFOLLOW | oflag, 0600); + if (fd == -1) + return (SEM_FAILED); + if (fstat(fd, &sb) == -1 || !S_ISREG(sb.st_mode)) { + close(fd); + errno = EINVAL; + return (SEM_FAILED); + } + if (sb.st_uid != geteuid()) { + close(fd); + errno = EPERM; + return (SEM_FAILED); + } + if (sb.st_size != (off_t)SEM_MMAP_SIZE) { + if (!(oflag & O_CREAT)) { + close(fd); + errno = EINVAL; + return (SEM_FAILED); + } + if (sb.st_size != 0) { + close(fd); + errno = EINVAL; + return (SEM_FAILED); + } + if (ftruncate(fd, SEM_MMAP_SIZE) == -1) { + close(fd); + errno = EINVAL; + return (SEM_FAILED); + } + + created = 1; + } + sem = mmap(NULL, SEM_MMAP_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + close(fd); + if (sem == MAP_FAILED) { + errno = EINVAL; + return (SEM_FAILED); + } + semp = malloc(sizeof(*semp)); + if (!semp) { + munmap(sem, SEM_MMAP_SIZE); + errno = ENOSPC; + return (SEM_FAILED); + } + if (created) { + phal_mutex_create(&sem->lock); + sem->value = value; + sem->shared = 1; + } + *semp = sem; + + return (semp); +#endif +} + +int +sem_close(sem_t *semp) +{ + sem_t sem; + + if (!semp || !(sem = *semp) || !sem->shared) { + errno = EINVAL; + return (-1); + } + + return ENOSYS; + //*semp = NULL; + //munmap(sem, SEM_MMAP_SIZE); + //free(semp); + + //return (0); +} + +int +sem_unlink(const char *name) +{ + //char sempath[SEM_PATH_SIZE]; + + return ENOSYS; + //makesempath(name, sempath, sizeof(sempath)); + //return (unlink(sempath)); +} diff --git a/pthread/rthread_sig.c b/pthread/rthread_sig.c new file mode 100644 index 00000000..80dd0183 --- /dev/null +++ b/pthread/rthread_sig.c @@ -0,0 +1,76 @@ +/* $OpenBSD: rthread_sig.c,v 1.18 2016/05/07 19:05:22 guenther Exp $ */ +/* + * Copyright (c) 2005 Ted Unangst + * 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 +#include + +#include + +#include "rthread.h" +//#include "cancel.h" /* in libc/include */ + +int +sigwait(const sigset_t *set, int *sig) +{ + sigset_t s = *set; + int ret; + + /*sigdelset(&s, SIGTHR); + do { + ENTER_CANCEL_POINT(1); + ret = __thrsigdivert(s, NULL, NULL); + LEAVE_CANCEL_POINT(ret == -1); + } while (ret == -1 && errno == EINTR); + if (ret == -1) + return (errno); + *sig = ret;*/ + // Is there even a signal system on the switch ? + return (ENOSYS); +} + +#if 0 /* need kernel to fill in more siginfo_t bits first */ +int +sigwaitinfo(const sigset_t *set, siginfo_t *info) +{ + sigset_t s = *set; + int ret; + + sigdelset(&s, SIGTHR); + ENTER_CANCEL_POINT(1); + ret = __thrsigdivert(s, info, NULL); + LEAVE_CANCEL_POINT(ret == -1); + return (ret); +} + +int +sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ + sigset_t s = *set; + int ret; + + sigdelset(&s, SIGTHR); + ENTER_CANCEL_POINT(1); + ret = __thrsigdivert(s, info, timeout); + LEAVE_CANCEL_POINT(ret == -1); + return (ret); +} +#endif diff --git a/pthread/rthread_spin_lock.c b/pthread/rthread_spin_lock.c new file mode 100644 index 00000000..9a18c096 --- /dev/null +++ b/pthread/rthread_spin_lock.c @@ -0,0 +1,115 @@ +/* $OpenBSD: rthread_spin_lock.c,v 1.4 2016/09/04 10:13:35 akfaew Exp $ */ +/* + * Copyright (c) 2012 Paul Irofti + * + * Permission to use, copy, modify, and/or 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. + */ + +#include +#include + +#include + +#include "rthread.h" + +int +pthread_spin_init(pthread_spinlock_t *lock, int pshared) +{ + pthread_spinlock_t l = NULL; + + if (lock == NULL) + return (EINVAL); + + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (ENOTSUP); + + l = calloc(1, sizeof *l); + if (l == NULL) + return (ENOMEM); + + l->lock = _SPINLOCK_UNLOCKED; + *lock = l; + return (0); +} + +int +pthread_spin_destroy(pthread_spinlock_t *lock) +{ + if (lock == NULL || *lock == NULL) + return (EINVAL); + + if ((*lock)->owner != NULL) + return (EBUSY); + + free(*lock); + *lock = NULL; + return (0); +} + +int +pthread_spin_trylock(pthread_spinlock_t *lock) +{ + pthread_t self = pthread_self(); + pthread_spinlock_t l; + + if (lock == NULL || *lock == NULL) + return (EINVAL); + + l = *lock; + + if (l->owner == self) + return (EDEADLK); + if (!_spinlocktry(&l->lock)) + return (EBUSY); + + l->owner = self; + return (0); +} + +int +pthread_spin_lock(pthread_spinlock_t *lock) +{ + pthread_t self = pthread_self(); + pthread_spinlock_t l; + + if (lock == NULL || *lock == NULL) + return (EINVAL); + + l = *lock; + + if (l->owner == self) + return (EDEADLK); + + _spinlock(&l->lock); + l->owner = self; + return (0); +} + +int +pthread_spin_unlock(pthread_spinlock_t *lock) +{ + pthread_t self = pthread_self(); + pthread_spinlock_t l; + + if (lock == NULL || *lock == NULL) + return (EINVAL); + + l = *lock; + + if (l->owner != self) + return (EPERM); + + l->owner = NULL; + _spinunlock(&l->lock); + return (0); +} diff --git a/pthread/rthread_stack.c b/pthread/rthread_stack.c new file mode 100644 index 00000000..1747b4d0 --- /dev/null +++ b/pthread/rthread_stack.c @@ -0,0 +1,135 @@ +/* $OpenBSD: rthread_stack.c,v 1.17 2017/09/05 02:40:54 guenther Exp $ */ + +/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman */ + +#include + +#include +#include +#include +#include +#include + +#include "rthread.h" + +/* + * Follow uthread's example and keep around stacks that have default + * attributes for possible reuse. + */ +static SLIST_HEAD(, stack) def_stacks = SLIST_HEAD_INITIALIZER(head); +static _atomic_lock_t def_stacks_lock = _SPINLOCK_UNLOCKED; + +struct stack * +_rthread_alloc_stack(pthread_t thread) +{ + struct stack *stack; + u_int32_t rnd; + caddr_t base; + caddr_t guard; + size_t size; + size_t guardsize; + + /* if the request uses the defaults, try to reuse one */ + if (thread->attr.stack_addr == NULL && + thread->attr.stack_size == RTHREAD_STACK_SIZE_DEF && + thread->attr.guard_size == _thread_pagesize) { + _spinlock(&def_stacks_lock); + stack = SLIST_FIRST(&def_stacks); + if (stack != NULL) { + SLIST_REMOVE_HEAD(&def_stacks, link); + _spinunlock(&def_stacks_lock); + return (stack); + } + _spinunlock(&def_stacks_lock); + } + + /* allocate the stack struct that we'll return */ + stack = malloc(sizeof(*stack)); + if (stack == NULL) + return (NULL); + + /* Smaller the stack, smaller the random bias */ + if (thread->attr.stack_size > _thread_pagesize) + rnd = arc4random() & (_thread_pagesize - 1); + else if (thread->attr.stack_size == _thread_pagesize) + rnd = arc4random() & (_thread_pagesize / 16 - 1); + else + rnd = 0; + rnd &= ~_STACKALIGNBYTES; + + /* If a stack address was provided, just fill in the details */ + if (thread->attr.stack_addr != NULL) { + stack->base = base = thread->attr.stack_addr; + stack->len = thread->attr.stack_size; +#ifdef MACHINE_STACK_GROWS_UP + stack->sp = base + rnd; +#else + stack->sp = base + thread->attr.stack_size - rnd; +#endif + /* + * This impossible guardsize marks this stack as + * application allocated so it won't be freed or + * cached by _rthread_free_stack() + */ + stack->guardsize = 1; + return (stack); + } + + /* round up the requested sizes up to full pages */ + size = ROUND_TO_PAGE(thread->attr.stack_size); + guardsize = ROUND_TO_PAGE(thread->attr.guard_size); + + /* check for overflow */ + if (size < thread->attr.stack_size || + guardsize < thread->attr.guard_size || + SIZE_MAX - size < guardsize) { + free(stack); + errno = EINVAL; + return (NULL); + } + size += guardsize; + + /* actually allocate the real stack */ + base = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (base == MAP_FAILED) { + free(stack); + return (NULL); + } + +#ifdef MACHINE_STACK_GROWS_UP + guard = base + size - guardsize; + stack->sp = base + rnd; +#else + guard = base; + stack->sp = base + size - rnd; +#endif + + /* memory protect the guard region */ + if (guardsize != 0 && mprotect(guard, guardsize, PROT_NONE) == -1) { + munmap(base, size); + free(stack); + return (NULL); + } + + stack->base = base; + stack->guardsize = guardsize; + stack->len = size; + return (stack); +} + +void +_rthread_free_stack(struct stack *stack) +{ + if (stack->len == RTHREAD_STACK_SIZE_DEF + stack->guardsize && + stack->guardsize == _thread_pagesize) { + _spinlock(&def_stacks_lock); + SLIST_INSERT_HEAD(&def_stacks, stack, link); + _spinunlock(&def_stacks_lock); + } else { + /* unmap the storage unless it was application allocated */ + if (stack->guardsize != 1) + munmap(stack->base, stack->len); + free(stack); + } +} diff --git a/pthread/rthread_sync.c b/pthread/rthread_sync.c new file mode 100644 index 00000000..041b1680 --- /dev/null +++ b/pthread/rthread_sync.c @@ -0,0 +1,682 @@ +/* $OpenBSD: rthread_sync.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * Copyright (c) 2012 Philip Guenther + * 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 and conditions - synchronization functions. + */ + +#include +#include +#include +#include +#include +#include + +#include "rthread.h" + +static _atomic_lock_t static_init_lock = _SPINLOCK_UNLOCKED; + +/* + * mutexen + */ +int +pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr) +{ + struct pthread_mutex *mutex; + + mutex = calloc(1, sizeof(*mutex)); + if (!mutex) + return (errno); + mutex->lock = _SPINLOCK_UNLOCKED; + TAILQ_INIT(&mutex->lockers); + if (attr == NULL) { + mutex->type = PTHREAD_MUTEX_DEFAULT; + mutex->prioceiling = -1; + } else { + mutex->type = (*attr)->ma_type; + mutex->prioceiling = (*attr)->ma_protocol == + PTHREAD_PRIO_PROTECT ? (*attr)->ma_prioceiling : -1; + } + *mutexp = mutex; + + return (0); +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutexp) +{ + struct pthread_mutex *mutex; + + assert(mutexp); + mutex = (struct pthread_mutex *)*mutexp; + if (mutex) { + if (mutex->count || mutex->owner != NULL || + !TAILQ_EMPTY(&mutex->lockers)) { +#define MSG "pthread_mutex_destroy on mutex with waiters!\n" + write(2, MSG, sizeof(MSG) - 1); +#undef MSG + return (EBUSY); + } + free(mutex); + *mutexp = NULL; + } + return (0); +} + +static int +_rthread_mutex_lock(pthread_mutex_t *mutexp, int trywait, + const struct timespec *abstime) +{ + struct pthread_mutex *mutex; + pthread_t self = pthread_self(); + int ret = 0; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization. Note: _thread_mutex_lock() in libc requires + * _rthread_mutex_lock() to perform the mutex init when *mutexp + * is NULL. + */ + if (*mutexp == NULL) { + _spinlock(&static_init_lock); + if (*mutexp == NULL) + ret = pthread_mutex_init(mutexp, NULL); + _spinunlock(&static_init_lock); + if (ret != 0) + return (EINVAL); + } + mutex = (struct pthread_mutex *)*mutexp; + + _rthread_debug(5, "%p: mutex_lock %p\n", (void *)self, (void *)mutex); + _spinlock(&mutex->lock); + if (mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers)) { + assert(mutex->count == 0); + mutex->owner = self; + } else if (mutex->owner == self) { + assert(mutex->count > 0); + + /* already owner? handle recursive behavior */ + if (mutex->type != PTHREAD_MUTEX_RECURSIVE) + { + if (trywait || + mutex->type == PTHREAD_MUTEX_ERRORCHECK) { + _spinunlock(&mutex->lock); + return (trywait ? EBUSY : EDEADLK); + } + + /* self-deadlock is disallowed by strict */ + if (mutex->type == PTHREAD_MUTEX_STRICT_NP && + abstime == NULL) + abort(); + + /* self-deadlock, possibly until timeout */ + while (__thrsleep(self, CLOCK_REALTIME, abstime, + &mutex->lock, NULL) != EWOULDBLOCK) + _spinlock(&mutex->lock); + return (ETIMEDOUT); + } + if (mutex->count == INT_MAX) { + _spinunlock(&mutex->lock); + return (EAGAIN); + } + } else if (trywait) { + /* try failed */ + _spinunlock(&mutex->lock); + return (EBUSY); + } else { + /* add to the wait queue and block until at the head */ + TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting); + while (mutex->owner != self) { + ret = __thrsleep(self, CLOCK_REALTIME, abstime, + &mutex->lock, NULL); + _spinlock(&mutex->lock); + assert(mutex->owner != NULL); + if (ret == EWOULDBLOCK) { + if (mutex->owner == self) + break; + TAILQ_REMOVE(&mutex->lockers, self, waiting); + _spinunlock(&mutex->lock); + return (ETIMEDOUT); + } + } + } + + mutex->count++; + _spinunlock(&mutex->lock); + + return (0); +} + +int +pthread_mutex_lock(pthread_mutex_t *p) +{ + return (_rthread_mutex_lock(p, 0, NULL)); +} + +int +pthread_mutex_trylock(pthread_mutex_t *p) +{ + return (_rthread_mutex_lock(p, 1, NULL)); +} + +int +pthread_mutex_timedlock(pthread_mutex_t *p, const struct timespec *abstime) +{ + return (_rthread_mutex_lock(p, 0, abstime)); +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutexp) +{ + pthread_t self = pthread_self(); + struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; + + _rthread_debug(5, "%p: mutex_unlock %p\n", (void *)self, + (void *)mutex); + + if (mutex == NULL) +#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK + return (EPERM); +#elif PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + return(0); +#else + abort(); +#endif + + if (mutex->owner != self) { + if (mutex->type == PTHREAD_MUTEX_ERRORCHECK || + mutex->type == PTHREAD_MUTEX_RECURSIVE) + return (EPERM); + else { + /* + * For mutex type NORMAL our undefined behavior for + * unlocking an unlocked mutex is to succeed without + * error. All other undefined behaviors are to + * abort() immediately. + */ + if (mutex->owner == NULL && + mutex->type == PTHREAD_MUTEX_NORMAL) + return (0); + else + abort(); + } + } + + if (--mutex->count == 0) { + pthread_t next; + + _spinlock(&mutex->lock); + mutex->owner = next = TAILQ_FIRST(&mutex->lockers); + if (next != NULL) + TAILQ_REMOVE(&mutex->lockers, next, waiting); + _spinunlock(&mutex->lock); + if (next != NULL) + __thrwakeup(next, 1); + } + + return (0); +} + +/* + * condition variables + */ +int +pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr) +{ + pthread_cond_t cond; + + cond = calloc(1, sizeof(*cond)); + if (!cond) + return (errno); + cond->lock = _SPINLOCK_UNLOCKED; + TAILQ_INIT(&cond->waiters); + if (attr == NULL) + cond->clock = CLOCK_REALTIME; + else + cond->clock = (*attr)->ca_clock; + *condp = cond; + + return (0); +} + +int +pthread_cond_destroy(pthread_cond_t *condp) +{ + pthread_cond_t cond; + + assert(condp); + cond = *condp; + if (cond) { + if (!TAILQ_EMPTY(&cond->waiters)) { +#define MSG "pthread_cond_destroy on condvar with waiters!\n" + write(2, MSG, sizeof(MSG) - 1); +#undef MSG + return (EBUSY); + } + free(cond); + } + *condp = NULL; + + return (0); +} + +int +pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, + const struct timespec *abstime) +{ + pthread_cond_t cond; + struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; + struct tib *tib = TIB_GET(); + pthread_t self = tib->tib_thread; + pthread_t next; + int mutex_count; + int canceled = 0; + int rv = 0; + int error; + PREP_CANCEL_POINT(tib); + + if (!*condp) + if ((error = pthread_cond_init(condp, NULL))) + return (error); + cond = *condp; + _rthread_debug(5, "%p: cond_timed %p,%p\n", (void *)self, + (void *)cond, (void *)mutex); + + if (mutex == NULL) +#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK + return (EPERM); +#else + abort(); +#endif + + if (mutex->owner != self) { + if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) + return (EPERM); + else + abort(); + } + + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + return (EINVAL); + + ENTER_DELAYED_CANCEL_POINT(tib, self); + + _spinlock(&cond->lock); + + /* mark the condvar as being associated with this mutex */ + if (cond->mutex == NULL) { + cond->mutex = mutex; + assert(TAILQ_EMPTY(&cond->waiters)); + } else if (cond->mutex != mutex) { + assert(cond->mutex == mutex); + _spinunlock(&cond->lock); + LEAVE_CANCEL_POINT_INNER(tib, 1); + return (EINVAL); + } else + assert(! TAILQ_EMPTY(&cond->waiters)); + + /* snag the count in case this is a recursive mutex */ + mutex_count = mutex->count; + + /* transfer from the mutex queue to the condvar queue */ + _spinlock(&mutex->lock); + self->blocking_cond = cond; + TAILQ_INSERT_TAIL(&cond->waiters, self, waiting); + _spinunlock(&cond->lock); + + /* wake the next guy blocked on the mutex */ + mutex->count = 0; + mutex->owner = next = TAILQ_FIRST(&mutex->lockers); + if (next != NULL) { + TAILQ_REMOVE(&mutex->lockers, next, waiting); + __thrwakeup(next, 1); + } + + /* wait until we're the owner of the mutex again */ + while (mutex->owner != self) { + error = __thrsleep(self, cond->clock, abstime, + &mutex->lock, &self->delayed_cancel); + + /* + * If abstime == NULL, then we're definitely waiting + * on the mutex instead of the condvar, and are + * just waiting for mutex ownership, regardless of + * why we woke up. + */ + if (abstime == NULL) { + _spinlock(&mutex->lock); + continue; + } + + /* + * If we took a normal signal (not from + * cancellation) then we should just go back to + * sleep without changing state (timeouts, etc). + */ + if (error == EINTR && (tib->tib_canceled == 0 || + (tib->tib_cantcancel & CANCEL_DISABLED))) { + _spinlock(&mutex->lock); + continue; + } + + /* + * The remaining reasons for waking up (normal + * wakeup, timeout, and cancellation) all mean that + * we won't be staying in the condvar queue and + * we'll no longer time out or be cancelable. + */ + abstime = NULL; + LEAVE_CANCEL_POINT_INNER(tib, 0); + + /* + * If we're no longer in the condvar's queue then + * we're just waiting for mutex ownership. Need + * cond->lock here to prevent race with cond_signal(). + */ + _spinlock(&cond->lock); + if (self->blocking_cond == NULL) { + _spinunlock(&cond->lock); + _spinlock(&mutex->lock); + continue; + } + assert(self->blocking_cond == cond); + + /* if timeout or canceled, make note of that */ + if (error == EWOULDBLOCK) + rv = ETIMEDOUT; + else if (error == EINTR) + canceled = 1; + + /* transfer between the queues */ + TAILQ_REMOVE(&cond->waiters, self, waiting); + assert(mutex == cond->mutex); + if (TAILQ_EMPTY(&cond->waiters)) + cond->mutex = NULL; + self->blocking_cond = NULL; + _spinunlock(&cond->lock); + _spinlock(&mutex->lock); + + /* mutex unlocked right now? */ + if (mutex->owner == NULL && + TAILQ_EMPTY(&mutex->lockers)) { + assert(mutex->count == 0); + mutex->owner = self; + break; + } + TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting); + } + + /* restore the mutex's count */ + mutex->count = mutex_count; + _spinunlock(&mutex->lock); + + LEAVE_CANCEL_POINT_INNER(tib, canceled); + + return (rv); +} + +int +pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) +{ + pthread_cond_t cond; + struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp; + struct tib *tib = TIB_GET(); + pthread_t self = tib->tib_thread; + pthread_t next; + int mutex_count; + int canceled = 0; + int error; + PREP_CANCEL_POINT(tib); + + if (!*condp) + if ((error = pthread_cond_init(condp, NULL))) + return (error); + cond = *condp; + _rthread_debug(5, "%p: cond_wait %p,%p\n", (void *)self, + (void *)cond, (void *)mutex); + + if (mutex == NULL) +#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK + return (EPERM); +#else + abort(); +#endif + + if (mutex->owner != self) { + if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) + return (EPERM); + else + abort(); + } + + ENTER_DELAYED_CANCEL_POINT(tib, self); + + _spinlock(&cond->lock); + + /* mark the condvar as being associated with this mutex */ + if (cond->mutex == NULL) { + cond->mutex = mutex; + assert(TAILQ_EMPTY(&cond->waiters)); + } else if (cond->mutex != mutex) { + assert(cond->mutex == mutex); + _spinunlock(&cond->lock); + LEAVE_CANCEL_POINT_INNER(tib, 1); + return (EINVAL); + } else + assert(! TAILQ_EMPTY(&cond->waiters)); + + /* snag the count in case this is a recursive mutex */ + mutex_count = mutex->count; + + /* transfer from the mutex queue to the condvar queue */ + _spinlock(&mutex->lock); + self->blocking_cond = cond; + TAILQ_INSERT_TAIL(&cond->waiters, self, waiting); + _spinunlock(&cond->lock); + + /* wake the next guy blocked on the mutex */ + mutex->count = 0; + mutex->owner = next = TAILQ_FIRST(&mutex->lockers); + if (next != NULL) { + TAILQ_REMOVE(&mutex->lockers, next, waiting); + __thrwakeup(next, 1); + } + + /* wait until we're the owner of the mutex again */ + while (mutex->owner != self) { + error = __thrsleep(self, 0, NULL, &mutex->lock, + &self->delayed_cancel); + + /* + * If we took a normal signal (not from + * cancellation) then we should just go back to + * sleep without changing state (timeouts, etc). + */ + if (error == EINTR && (tib->tib_canceled == 0 || + (tib->tib_cantcancel & CANCEL_DISABLED))) { + _spinlock(&mutex->lock); + continue; + } + + /* + * The remaining reasons for waking up (normal + * wakeup and cancellation) all mean that we won't + * be staying in the condvar queue and we'll no + * longer be cancelable. + */ + LEAVE_CANCEL_POINT_INNER(tib, 0); + + /* + * If we're no longer in the condvar's queue then + * we're just waiting for mutex ownership. Need + * cond->lock here to prevent race with cond_signal(). + */ + _spinlock(&cond->lock); + if (self->blocking_cond == NULL) { + _spinunlock(&cond->lock); + _spinlock(&mutex->lock); + continue; + } + assert(self->blocking_cond == cond); + + /* if canceled, make note of that */ + if (error == EINTR) + canceled = 1; + + /* transfer between the queues */ + TAILQ_REMOVE(&cond->waiters, self, waiting); + assert(mutex == cond->mutex); + if (TAILQ_EMPTY(&cond->waiters)) + cond->mutex = NULL; + self->blocking_cond = NULL; + _spinunlock(&cond->lock); + _spinlock(&mutex->lock); + + /* mutex unlocked right now? */ + if (mutex->owner == NULL && + TAILQ_EMPTY(&mutex->lockers)) { + assert(mutex->count == 0); + mutex->owner = self; + break; + } + TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting); + } + + /* restore the mutex's count */ + mutex->count = mutex_count; + _spinunlock(&mutex->lock); + + LEAVE_CANCEL_POINT_INNER(tib, canceled); + + return (0); +} + + +int +pthread_cond_signal(pthread_cond_t *condp) +{ + pthread_cond_t cond; + struct pthread_mutex *mutex; + pthread_t thread; + int wakeup; + + /* uninitialized? Then there's obviously no one waiting! */ + if (!*condp) + return 0; + + cond = *condp; + _rthread_debug(5, "%p: cond_signal %p,%p\n", (void *)pthread_self(), + (void *)cond, (void *)cond->mutex); + _spinlock(&cond->lock); + thread = TAILQ_FIRST(&cond->waiters); + if (thread == NULL) { + assert(cond->mutex == NULL); + _spinunlock(&cond->lock); + return (0); + } + + assert(thread->blocking_cond == cond); + TAILQ_REMOVE(&cond->waiters, thread, waiting); + thread->blocking_cond = NULL; + + mutex = cond->mutex; + assert(mutex != NULL); + if (TAILQ_EMPTY(&cond->waiters)) + cond->mutex = NULL; + + /* link locks to prevent race with timedwait */ + _spinlock(&mutex->lock); + _spinunlock(&cond->lock); + + wakeup = mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers); + if (wakeup) + mutex->owner = thread; + else + TAILQ_INSERT_TAIL(&mutex->lockers, thread, waiting); + _spinunlock(&mutex->lock); + if (wakeup) + __thrwakeup(thread, 1); + + return (0); +} + +int +pthread_cond_broadcast(pthread_cond_t *condp) +{ + pthread_cond_t cond; + struct pthread_mutex *mutex; + pthread_t thread; + pthread_t p; + int wakeup; + + /* uninitialized? Then there's obviously no one waiting! */ + if (!*condp) + return 0; + + cond = *condp; + _rthread_debug(5, "%p: cond_broadcast %p,%p\n", (void *)pthread_self(), + (void *)cond, (void *)cond->mutex); + _spinlock(&cond->lock); + thread = TAILQ_FIRST(&cond->waiters); + if (thread == NULL) { + assert(cond->mutex == NULL); + _spinunlock(&cond->lock); + return (0); + } + + mutex = cond->mutex; + assert(mutex != NULL); + + /* walk the list, clearing the "blocked on condvar" pointer */ + p = thread; + do + p->blocking_cond = NULL; + while ((p = TAILQ_NEXT(p, waiting)) != NULL); + + /* + * We want to transfer all the threads from the condvar's list + * to the mutex's list. The TAILQ_* macros don't let us do that + * efficiently, so this is direct list surgery. Pay attention! + */ + + /* 1) attach the first thread to the end of the mutex's list */ + _spinlock(&mutex->lock); + wakeup = mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers); + thread->waiting.tqe_prev = mutex->lockers.tqh_last; + *(mutex->lockers.tqh_last) = thread; + + /* 2) fix up the end pointer for the mutex's list */ + mutex->lockers.tqh_last = cond->waiters.tqh_last; + + if (wakeup) { + TAILQ_REMOVE(&mutex->lockers, thread, waiting); + mutex->owner = thread; + _spinunlock(&mutex->lock); + __thrwakeup(thread, 1); + } else + _spinunlock(&mutex->lock); + + /* 3) reset the condvar's list and mutex pointer */ + TAILQ_INIT(&cond->waiters); + assert(cond->mutex != NULL); + cond->mutex = NULL; + _spinunlock(&cond->lock); + + return (0); +} diff --git a/pthread/rthread_thread.c b/pthread/rthread_thread.c new file mode 100644 index 00000000..a2b13591 --- /dev/null +++ b/pthread/rthread_thread.c @@ -0,0 +1,596 @@ +/* $OpenBSD: rthread.c,v 1.99 2017/11/04 22:53:57 jca Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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 +#ifndef NO_PIC +#include +#pragma weak _DYNAMIC +#endif + +#include +#include +#include +#include +#include +#include +//#include + +#include + +#include "rthread.h" + +static int concurrency_level; /* not used */ + +int _threads_ready; +int _post_threaded; +size_t _thread_pagesize; +struct listhead _thread_list = LIST_HEAD_INITIALIZER(_thread_list); +_atomic_lock_t _thread_lock = _SPINLOCK_UNLOCKED; +static struct pthread_queue _thread_gc_list + = TAILQ_HEAD_INITIALIZER(_thread_gc_list); +static _atomic_lock_t _thread_gc_lock = _SPINLOCK_UNLOCKED; + +struct pthread_attr _rthread_attr_default = { + .stack_addr = NULL, + .stack_size = RTHREAD_STACK_SIZE_DEF, +/* .guard_size set in _rthread_init */ + .detach_state = PTHREAD_CREATE_JOINABLE, + .contention_scope = PTHREAD_SCOPE_SYSTEM, + .sched_policy = SCHED_OTHER, + .sched_param = { .sched_priority = 0 }, + .sched_inherit = PTHREAD_INHERIT_SCHED, +}; + +/* + * internal support functions + */ + +static void +_rthread_start(void *v) +{ + pthread_t thread = v; + void **tls = phal_get_tls(); + void *retval; + + // Setup tls + *tls = thread; + retval = thread->fn(thread->arg); + pthread_exit(retval); +} + +static void +sigthr_handler(__unused int sig) +{ + pthread_t self = pthread_self(); + + /* + * Do nothing unless + * 1) pthread_cancel() has been called on this thread, + * 2) cancelation is enabled for it, and + * 3) we're not already in cancelation processing + */ + if (!self->tib_canceled || self->tib_cantcancel) + return; + + /* + * If delaying cancels inside complex ops (pthread_cond_wait, + * pthread_join, etc), just mark that this has happened to + * prevent a race with going to sleep + */ + if (self->tib_cancel_point & CANCEL_POINT_DELAYED) { + self->delayed_cancel = 1; + return; + } + + /* + * otherwise, if in a cancel point or async cancels are + * enabled, then exit + */ + if (self->tib_cancel_point || + (self->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL)) + pthread_exit(PTHREAD_CANCELED); +} + + +/* + * A few basic callbacks for libc. The first couple are only used + * on archs where there isn't a fast TCB_GET() + */ +#ifndef TCB_HAVE_MD_GET +static int * +multi_threaded_errnoptr(void) +{ + return &pthread_self()->tib_errno; +} + +/*static void * +multi_threaded_tcb(void) +{ + return (TCB_GET()); +}*/ +#endif /* TCB_HAVE_MD_GET */ + +static void +_rthread_free(pthread_t thread) +{ + _spinlock(&_thread_gc_lock); + TAILQ_INSERT_TAIL(&_thread_gc_list, thread, waiting); + _spinunlock(&_thread_gc_lock); +} + +void +_rthread_release(pthread_t thread) +{ + _spinlock(&_thread_lock); + LIST_REMOVE(thread, threads); + _spinunlock(&_thread_lock); + + _spinlock(&thread->flags_lock); + if (thread->flags & THREAD_DETACHED) { + _spinunlock(&thread->flags_lock); + _rthread_free(thread); + } else { + thread->flags |= THREAD_DONE; + _spinunlock(&thread->flags_lock); + _sem_post(&thread->donesem); + } +} + +static void +_thread_key_zero(int key) +{ + pthread_t thread; + struct rthread_storage *rs; + + LIST_FOREACH(thread, &_thread_list, threads) { + for (rs = thread->local_storage; rs; rs = rs->next) { + if (rs->keyid == key) + rs->data = NULL; + } + } +} + +void +_rthread_init(void) +{ + pthread_t thread = pthread_self(); + struct sigaction sa; + + if (_threads_ready) + return; + + LIST_INSERT_HEAD(&_thread_list, thread, threads); + + //_thread_pagesize = (size_t)sysconf(_SC_PAGESIZE); + _rthread_attr_default.guard_size = 0;//_thread_pagesize; + thread->attr = _rthread_attr_default; + + /* get libc to start using our callbacks */ + /*{ + struct thread_callbacks cb = { 0 }; + +#ifndef TCB_HAVE_MD_GET + cb.tc_errnoptr = multi_threaded_errnoptr; + cb.tc_tcb = multi_threaded_tcb; +#endif + cb.tc_fork = _thread_fork; + cb.tc_vfork = _thread_vfork; + cb.tc_thread_release = _thread_release; + cb.tc_thread_key_zero = _thread_key_zero; + _thread_set_callbacks(&cb, sizeof(cb)); + } + +#ifndef NO_PIC + if (_DYNAMIC) { + dlctl(NULL, DL_SETTHREADLCK, _rthread_dl_lock); + } +#endif + */ + /* + * Set the handler on the signal used for cancelation and + * suspension, and make sure it's unblocked + */ + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = sigthr_handler; + //sigaction(SIGTHR, &sa, NULL); + //sigaddset(&sa.sa_mask, SIGTHR); + //sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); + + _threads_ready = 1; + + _rthread_debug(1, "rthread init\n"); +} + +static void +_rthread_reaper(void) +{ + pthread_t thread; + +restart: + _spinlock(&_thread_gc_lock); + TAILQ_FOREACH(thread, &_thread_gc_list, waiting) { + if (!(thread->flags & THREAD_DONE)) + continue; + TAILQ_REMOVE(&_thread_gc_list, thread, waiting); + _spinunlock(&_thread_gc_lock); + if (thread != &_initial_thread) { + _rthread_debug(3, "rthread reaping %p stack %p\n", + (void *)thread, (void *)thread->stack); + // TODO: stack and tib + //_rthread_free_stack(thread->stack); + //_dl_free_tib(thread->tib, sizeof(*thread)); + int res = phal_thread_destroy(&thread->tib_tid); + if (res) + _rthread_debug(3, "Failed to free tid of %p: %d", thread, res); + free(thread); + } else { + /* initial thread isn't part of TIB allocation */ + _rthread_debug(3, "rthread reaping %p (initial)\n", + (void *)thread); + //_dl_free_tib(thread->tib, 0); + } + goto restart; + } + _spinunlock(&_thread_gc_lock); +} + +/* + * real pthread functions + */ + +int +pthread_join(pthread_t thread, void **retval) +{ + int e; + pthread_t self; + //PREP_CANCEL_POINT(tib); + + if (_post_threaded) { +#define GREATSCOTT "great scott! serious repercussions on future events!\n" + write(2, GREATSCOTT, sizeof(GREATSCOTT) - 1); + abort(); + } + if (!_threads_ready) + _rthread_init(); + self = pthread_self(); + + e = 0; + //ENTER_DELAYED_CANCEL_POINT(tib, self); + if (thread == NULL) + e = EINVAL; + else if (thread == self) + e = EDEADLK; + else if (thread->flags & THREAD_DETACHED) + e = EINVAL; + else if ((e = _sem_wait(&thread->donesem, 0, NULL, + &self->delayed_cancel)) == 0) { + if (retval) + *retval = thread->retval; + + /* + * We should be the last having a ref to this thread, + * but someone stupid or evil might haved detached it; + * in that case the thread will clean up itself + */ + if ((thread->flags & THREAD_DETACHED) == 0) + _rthread_free(thread); + } + + //LEAVE_CANCEL_POINT_INNER(tib, e); + _rthread_reaper(); + return (e); +} + +int +pthread_detach(pthread_t thread) +{ + int rc = 0; + + _spinlock(&thread->flags_lock); + if (thread->flags & THREAD_DETACHED) { + rc = EINVAL; + _spinunlock(&thread->flags_lock); + } else if (thread->flags & THREAD_DONE) { + _spinunlock(&thread->flags_lock); + _rthread_free(thread); + } else { + thread->flags |= THREAD_DETACHED; + _spinunlock(&thread->flags_lock); + } + _rthread_reaper(); + return (rc); +} + +int +pthread_create(pthread_t *threadp, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + //extern int __isthreaded; + pthread_t thread; + int rc; + + if (!_threads_ready) + _rthread_init(); + + _rthread_reaper(); + + thread = malloc(sizeof(*thread)); + if (thread == NULL) + return (ENOMEM); + memset(thread, 0, sizeof(*thread)); + //thread->donesem.lock = _SPINLOCK_UNLOCKED; + thread->flags_lock = _SPINLOCK_UNLOCKED; + thread->fn = start_routine; + thread->arg = arg; + + thread->attr = attr != NULL ? *(*attr) : _rthread_attr_default; + if (thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) { + pthread_t self = pthread_self(); + + thread->attr.sched_policy = self->attr.sched_policy; + thread->attr.sched_param = self->attr.sched_param; + } + if (thread->attr.detach_state == PTHREAD_CREATE_DETACHED) + thread->flags |= THREAD_DETACHED; + + // TODO: Stack allocation. + /*thread->stack = _rthread_alloc_stack(thread); + if (!thread->stack) { + rc = errno; + goto fail1; + }*/ + + _spinlock(&_thread_lock); + LIST_INSERT_HEAD(&_thread_list, thread, threads); + _spinunlock(&_thread_lock); + + /* we're going to be multi-threaded real soon now */ + //__isthreaded = 1; + + rc = phal_thread_create(&thread->tib_tid, _rthread_start, thread); + if (rc == 0) { + /* success */ + *threadp = thread; + return (0); + } + + _spinlock(&_thread_lock); + LIST_REMOVE(thread, threads); + _spinunlock(&_thread_lock); + //_rthread_free_stack(thread->stack); +fail1: + free(thread); + return (rc); +} + +int +pthread_kill(pthread_t thread, int sig) +{ + return ENOSYS; +#if 0 + struct tib *tib = thread->tib; + + if (sig == SIGTHR) + return (EINVAL); + if (thrkill(tib->tib_tid, sig, TIB_TO_TCB(tib))) + return (errno); + return (0); +#endif +} + +int +pthread_cancel(pthread_t thread) +{ + return ENOSYS; +#if 0 + struct tib *tib = thread->tib; + pid_t tid = tib->tib_tid; + + if (tib->tib_canceled == 0 && tid != 0 && + (tib->tib_cantcancel & CANCEL_DYING) == 0) { + tib->tib_canceled = 1; + + if ((tib->tib_cantcancel & CANCEL_DISABLED) == 0) { + thrkill(tid, SIGTHR, TIB_TO_TCB(tib)); + return (0); + } + } + return (0); +#endif +} + +void +pthread_testcancel(void) +{ + /*struct tib *tib = TIB_GET(); + + if (tib->tib_canceled && (tib->tib_cantcancel & CANCEL_DISABLED) == 0) + pthread_exit(PTHREAD_CANCELED);*/ +} + +int +pthread_setcancelstate(int state, int *oldstatep) +{ + pthread_t self = pthread_self(); + int oldstate; + + if (self == NULL) + return (EINVAL); + oldstate = self->tib_cantcancel & CANCEL_DISABLED ? + PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE; + if (state == PTHREAD_CANCEL_ENABLE) { + self->tib_cantcancel &= ~CANCEL_DISABLED; + } else if (state == PTHREAD_CANCEL_DISABLE) { + self->tib_cantcancel |= CANCEL_DISABLED; + } else { + return (EINVAL); + } + if (oldstatep) + *oldstatep = oldstate; + + return (0); +} + +int +pthread_setcanceltype(int type, int *oldtypep) +{ + return ENOSYS; +#if 0 + struct tib *tib = TIB_GET(); + int oldtype; + + oldtype = tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL ? + PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED; + if (type == PTHREAD_CANCEL_DEFERRED) { + tib->tib_thread_flags &=~ TIB_THREAD_ASYNC_CANCEL; + } else if (type == PTHREAD_CANCEL_ASYNCHRONOUS) { + tib->tib_thread_flags |= TIB_THREAD_ASYNC_CANCEL; + } else { + return (EINVAL); + } + if (oldtypep) + *oldtypep = oldtype; + + return (0); +#endif +} + +void +pthread_cleanup_push(void (*fn)(void *), void *arg) +{ + struct rthread_cleanup_fn *clfn; + pthread_t self = pthread_self(); + + clfn = calloc(1, sizeof(*clfn)); + if (!clfn) + return; + clfn->fn = fn; + clfn->arg = arg; + clfn->next = self->cleanup_fns; + self->cleanup_fns = clfn; +} + +void +pthread_cleanup_pop(int execute) +{ + struct rthread_cleanup_fn *clfn; + pthread_t self = pthread_self(); + + clfn = self->cleanup_fns; + if (clfn) { + self->cleanup_fns = clfn->next; + if (execute) + clfn->fn(clfn->arg); + free(clfn); + } +} + +int +pthread_getconcurrency(void) +{ + return (concurrency_level); +} + +int +pthread_setconcurrency(int new_level) +{ + if (new_level < 0) + return (EINVAL); + concurrency_level = new_level; + return (0); +} + +/* + * compat debug stuff + */ +void +_thread_dump_info(void) +{ + pthread_t thread; + + _spinlock(&_thread_lock); + LIST_FOREACH(thread, &_thread_list, threads) + printf("thread %p flags 0x%x name %s\n", thread, + thread->tib_thread_flags, thread->name); + _spinunlock(&_thread_lock); +} + +#if 0 +#ifndef NO_PIC +/* + * _rthread_dl_lock() provides the locking for dlopen(), dlclose(), and + * the function called via atexit() to invoke all destructors. The latter + * two call shared-object destructors, which may need to call dlclose(), + * so this lock needs to permit recursive locking. + * The specific code here was extracted from _rthread_mutex_lock() and + * pthread_mutex_unlock() and simplified to use the static variables. + */ +void +_rthread_dl_lock(int what) +{ + static _atomic_lock_t lock = _SPINLOCK_UNLOCKED; + static pthread_t owner = NULL; + static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers); + static int count = 0; + + if (what == 0) { + pthread_t self = pthread_self(); + + /* lock, possibly recursive */ + _spinlock(&lock); + if (owner == NULL) { + owner = self; + } else if (owner != self) { + TAILQ_INSERT_TAIL(&lockers, self, waiting); + while (owner != self) { + // TODO: __thrsleep + return ENOSYS; + //__thrsleep(self, 0, NULL, &lock, NULL); + _spinlock(&lock); + } + } + count++; + _spinunlock(&lock); + } else if (what == 1) { + /* unlock, possibly recursive */ + if (--count == 0) { + pthread_t next; + + _spinlock(&lock); + owner = next = TAILQ_FIRST(&lockers); + if (next != NULL) + TAILQ_REMOVE(&lockers, next, waiting); + _spinunlock(&lock); + if (next != NULL) + __thrwakeup(next, 1); + } + } else { + /* reinit: used in child after fork to clear the queue */ + lock = _SPINLOCK_UNLOCKED; + if (--count == 0) + owner = NULL; + TAILQ_INIT(&lockers); + } +} +#endif +#endif diff --git a/pthread/rthread_tls.c b/pthread/rthread_tls.c new file mode 100644 index 00000000..db5e024e --- /dev/null +++ b/pthread/rthread_tls.c @@ -0,0 +1,185 @@ +/* $OpenBSD: rthread_tls.c,v 1.4 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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 +#include +#include + +#include +#include + +#include "rthread.h" + + +struct rthread_key { + int used; + void (*destructor)(void *); +}; + +static struct rthread_key rkeys[PTHREAD_KEYS_MAX]; +static _atomic_lock_t rkeyslock = _SPINLOCK_UNLOCKED; + +int +pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) +{ + static int hint; + int i; + + _spinlock(&rkeyslock); + if (rkeys[hint].used) { + for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (!rkeys[i].used) + break; + } + if (i == PTHREAD_KEYS_MAX) { + _spinunlock(&rkeyslock); + return (EAGAIN); + } + hint = i; + } + rkeys[hint].used = 1; + rkeys[hint].destructor = destructor; + + *key = hint++; + if (hint >= PTHREAD_KEYS_MAX) + hint = 0; + _spinunlock(&rkeyslock); + + return (0); +} + +int +pthread_key_delete(pthread_key_t key) +{ + struct rthread_storage *rs; + int rv = 0; + + if (key < 0 || key >= PTHREAD_KEYS_MAX) + return (EINVAL); + + _spinlock(&rkeyslock); + if (!rkeys[key].used) { + rv = EINVAL; + goto out; + } + + rkeys[key].used = 0; + rkeys[key].destructor = NULL; + for (rs = _initial_thread.local_storage; rs; rs = rs->next) { + if (rs->keyid == key) + rs->data = NULL; + } + +out: + _spinunlock(&rkeyslock); + return (rv); +} + +static struct rthread_storage * +_rthread_findstorage(pthread_key_t key) +{ + struct rthread_storage *rs; + pthread_t self; + + if (!rkeys[key].used) { + rs = NULL; + goto out; + } + + self = pthread_self(); + + for (rs = self->local_storage; rs; rs = rs->next) { + if (rs->keyid == key) + break; + } + if (!rs) { + rs = calloc(1, sizeof(*rs)); + if (!rs) + goto out; + rs->keyid = key; + rs->data = NULL; + rs->next = self->local_storage; + self->local_storage = rs; + } + +out: + return (rs); +} + +void * +pthread_getspecific(pthread_key_t key) +{ + struct rthread_storage *rs; + + if (key < 0 || key >= PTHREAD_KEYS_MAX) + return (NULL); + + 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; + + if (key < 0 || key >= PTHREAD_KEYS_MAX) + return (EINVAL); + + rs = _rthread_findstorage(key); + if (!rs) + return (ENOMEM); + rs->data = (void *)data; + + return (0); +} + +void +_rthread_tls_destructors(pthread_t thread) +{ + struct rthread_storage *rs; + int i; + + _spinlock(&rkeyslock); + for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS; i++) { + for (rs = thread->local_storage; rs; rs = rs->next) { + if (!rs->data) + continue; + if (rkeys[rs->keyid].destructor) { + void (*destructor)(void *) = + rkeys[rs->keyid].destructor; + void *data = rs->data; + rs->data = NULL; + _spinunlock(&rkeyslock); + destructor(data); + _spinlock(&rkeyslock); + } + } + } + for (rs = thread->local_storage; rs; rs = thread->local_storage) { + thread->local_storage = rs->next; + free(rs); + } + _spinunlock(&rkeyslock); +} diff --git a/pthread/sched_prio.c b/pthread/sched_prio.c new file mode 100644 index 00000000..96e45142 --- /dev/null +++ b/pthread/sched_prio.c @@ -0,0 +1,44 @@ +/* $OpenBSD: sched_prio.c,v 1.1 2011/11/06 12:15:51 guenther Exp $ */ + +/* + * Copyright (c) 2010 Federico G. Schwindt + * + * 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. + */ + +#include +#include +#include "rthread.h" + +int +sched_get_priority_max(int policy) +{ + if (policy < SCHED_FIFO || policy > SCHED_RR) { + errno = EINVAL; + return (-1); + } + return (PTHREAD_MAX_PRIORITY); +} + +int +sched_get_priority_min(int policy) +{ + if (policy < SCHED_FIFO || policy > SCHED_RR) { + errno = EINVAL; + return (-1); + } + return (PTHREAD_MIN_PRIORITY); +} + diff --git a/pthread/semaphore.h b/pthread/semaphore.h new file mode 100644 index 00000000..6a92d19a --- /dev/null +++ b/pthread/semaphore.h @@ -0,0 +1,60 @@ +/* $OpenBSD: semaphore.h,v 1.1 2017/10/15 23:40:33 guenther Exp $ */ + +/* semaphore.h: POSIX 1003.1b semaphores */ + +/*- + * Copyright (c) 1996, 1997 + * HD Associates, Inc. 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 HD Associates, Inc + * 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 HD ASSOCIATES 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 HD ASSOCIATES 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. + */ + +#ifndef _SEMAPHORE_H_ +#define _SEMAPHORE_H_ + +#include + +/* Opaque type definition. */ +struct __sem; +typedef struct __sem *sem_t; +struct timespec; + +#define SEM_FAILED ((sem_t *)0) + +int sem_init(sem_t *, int, unsigned int); +int sem_destroy(sem_t *); +sem_t *sem_open(const char *, int, ...); +int sem_close(sem_t *); +int sem_unlink(const char *); +int sem_wait(sem_t *); +int sem_timedwait(sem_t * __restrict, const struct timespec * __restrict); +int sem_trywait(sem_t *); +int sem_post(sem_t *); +int sem_getvalue(sem_t * __restrict, int * __restrict); + +#endif /* _SEMAPHORE_H_ */ diff --git a/pthread/shlib_version b/pthread/shlib_version new file mode 100644 index 00000000..970cef2a --- /dev/null +++ b/pthread/shlib_version @@ -0,0 +1,2 @@ +major=25 +minor=1 diff --git a/pthread/spinlock.h b/pthread/spinlock.h new file mode 100644 index 00000000..87a3a1f0 --- /dev/null +++ b/pthread/spinlock.h @@ -0,0 +1,5 @@ +#pragma once + +#define _ATOMIC_LOCK_UNLOCKED (0) +#define _ATOMIC_LOCK_LOCKED (1) +typedef int _atomic_lock_t; diff --git a/pthread/synch.h b/pthread/synch.h new file mode 100644 index 00000000..ffb91e19 --- /dev/null +++ b/pthread/synch.h @@ -0,0 +1,67 @@ +/* $OpenBSD: synch.h,v 1.2 2017/09/05 02:40:54 guenther Exp $ */ +/* + * Copyright (c) 2017 Martin Pieuchot + * + * 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. + */ + +/*#include +#include +#include +*/ +#if 0 +static inline int +_wake(volatile uint32_t *p, int n) +{ + //return futex(p, FUTEX_WAKE, n, NULL, NULL); + return ENOSYS; +} + +static inline void +_wait(volatile uint32_t *p, int val) +{ + /*while (*p != (uint32_t)val) + futex(p, FUTEX_WAIT, val, NULL, NULL);*/ + return; +} + +static inline int +_twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *abs) +{ + /*struct timespec rel; + + if (abs == NULL) + return futex(p, FUTEX_WAIT, val, NULL, NULL); + + if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel)) + return (EINVAL); + + rel.tv_sec = abs->tv_sec - rel.tv_sec; + if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) { + rel.tv_sec--; + rel.tv_nsec += 1000000000; + } + if (rel.tv_sec < 0) + return (ETIMEDOUT); + + return futex(p, FUTEX_WAIT, val, &rel, NULL);*/ + return ENOSYS; +} + +static inline int +_requeue(volatile uint32_t *p, int n, int m, volatile uint32_t *q) +{ + //return futex(p, FUTEX_REQUEUE, n, (void *)(long)m, q); + return ENOSYS; +} +#endif diff --git a/pthread/sys/switch/phal.c b/pthread/sys/switch/phal.c new file mode 100644 index 00000000..f0219827 --- /dev/null +++ b/pthread/sys/switch/phal.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include +#include +#include "thread_private.h" +#include "phal.h" + +static int result_to_errno(result_t res) { + switch (res) { + case RESULT_OK: return 0; + case 0xEA01: return ETIMEDOUT; + default: return ENOSYS; + } +} + +// TODO: better error handling. Need to turn libtransistor error into unix +// errors. + +int phal_thread_create(phal_tid *tid, void (*start_routine)(void*), void *arg) { + int ret; + tid->stack = malloc(0x2000); + if (tid->stack == NULL) + return ENOMEM; + ret = result_to_errno(svcCreateThread(&tid->id, start_routine, (uint64_t)arg, tid->stack + 0x2000, 0x1F, -2)); + if (ret) + return ret; + return result_to_errno(svcStartThread(tid->id)); +} + +// Noreturn ! +void phal_thread_exit(phal_tid *tid) { + svcExitThread(); +} + +int phal_thread_destroy(phal_tid *tid) { + free(tid->stack); + return result_to_errno(svcCloseHandle(tid->id)); +} + +int phal_thread_sleep(uint64_t msec) { + uint64_t nanos = msec * 1000 * 1000; + return result_to_errno(svcSleepThread(nanos)); +} + +int phal_semaphore_create(phal_semaphore *sem) { + sem->lock = 0; + sem->sem = 0; + return 0; +} + +int phal_semaphore_destroy(phal_semaphore *sem) { return 0; } + +/// Wake up one thread waiting for the semaphore. +int phal_semaphore_signal(phal_semaphore *sem) { + int ret; + if ((ret = result_to_errno(svcSignalProcessWideKey(&sem->sem, 1))) != 0) + return ret; + + // Avoid the kernel's "pre-signaling" support. This should only be + // called with the associated mutex locked, so this is safe. + sem->sem = 0; + return ret; +} + +int phal_semaphore_broadcast(phal_semaphore *sem) { + int ret; + if ((ret = phal_semaphore_lock(sem)) != 0) + return ret; + if ((ret = result_to_errno(svcSignalProcessWideKey(&sem->sem, 1))) != 0) + return ret; + + // Avoid the kernel's "pre-signaling" support. This should only be + // called with the associated mutex locked, so this is safe. + sem->sem = 0; + if ((ret = phal_semaphore_unlock(sem)) != 0) + return ret; + return ret; +} + +static int timespec_subtract (struct timespec *result, const struct timespec *x, struct timespec *y) { + /* Perform the carry for the later subtraction by updating y. */ + if (x->tv_nsec < y->tv_nsec) { + int sec = (y->tv_nsec - x->tv_nsec) / 1000 * 1000 * 1000 + 1; + y->tv_nsec -= 1000 * 1000 * 1000 * sec; + y->tv_sec += sec; + } + if (x->tv_nsec - y->tv_nsec > 1000 * 1000 * 1000) { + int sec = (y->tv_nsec - x->tv_nsec) / 1000 * 1000 * 1000; + y->tv_nsec += 1000 * 1000 * 1000 * sec; + y->tv_sec -= sec; + } + + /* Compute the time remaining to wait. + tv_usec is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_nsec = x->tv_nsec - y->tv_nsec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} + +// TODO: This kinda sucks. Different platform behave differently here. For now +// let's focus on the switch, which needs a locked mutex and a semaphore. +/// Wait for the semaphore to be signaled. Note that we should **not** wake up +/// if a signal was previously sent. This is not a counting semaphore. +int phal_semaphore_wait(phal_semaphore *sem, const struct timespec *abstime) { + uint64_t nsec = 0; + struct timeval curtime; + struct timespec curtimespec; + struct timespec result; + + if (abstime) { + gettimeofday(&curtime, NULL); + curtimespec.tv_sec = curtime.tv_sec; + curtimespec.tv_nsec = curtime.tv_usec * 1000; + if (timespec_subtract(&result, abstime, &curtimespec)) { + // Negative result, set nsec to 0 + nsec = 0; + } else { + nsec += result.tv_sec * 1000 * 1000 * 1000; + nsec += result.tv_nsec; + } + } else { + // No timeout, set nsec to max value. + nsec = -1; + } + + // Mutex must be locked at this point, otherwise shit stinks. + pthread_t self = pthread_self(); + return result_to_errno(svcWaitProcessWideKeyAtomic(&sem->lock, &sem->sem, self->tib_tid.id, nsec)); + // At this point, lock is still locked, and still ours ! +} + +/*int phal_mutex_create(phal_mutex *mutex) { + *mutex = 0; + return 0; +} + +int phal_mutex_destroy(phal_mutex *mutex) { return 0; } +*/ +#define HAS_LISTENERS 0x40000000 + +int phal_semaphore_lock(phal_semaphore *sem) { + pthread_t self = pthread_self(); + _Atomic(uint32_t) *mutex = &sem->lock; + + while (1) { + uint32_t cur = 0; + if (atomic_compare_exchange_strong(mutex, &cur, self->tib_tid.id)) { + // We won the race! + return 0; + } + + if ((cur &~ HAS_LISTENERS) == self->tib_tid.id) { + // Kernel assigned it to us! + return 0; + } + + if (!(cur & HAS_LISTENERS)) { + // The flag is not set, we need to set it. + if (!atomic_compare_exchange_strong(mutex, &cur, cur | HAS_LISTENERS)) { + continue; + } + } + svcArbitrateLock(cur &~ HAS_LISTENERS, mutex, self->tib_tid.id); + } +} + +int phal_semaphore_unlock(phal_semaphore *sem) { + _Atomic(uint32_t) *mutex = &sem->lock; + dbg_printf("%p Unlocked semaphore\n", sem); + uint32_t old = atomic_exchange(mutex, 0); + if (old & HAS_LISTENERS) + svcArbitrateUnlock(mutex); + return 0; +} + +void **phal_get_tls() { + struct tls *tls = get_tls(); + if (tls == NULL) + return NULL; + if (tls->ctx != NULL) + return &tls->ctx->pthread; + tls->ctx = malloc(sizeof(struct thread_ctx)); + if (tls->ctx == NULL) + return NULL; + tls->ctx->pthread = NULL; + _REENT_INIT_PTR(&tls->ctx->reent); + return &tls->ctx->pthread; +} diff --git a/pthread/sys/switch/phal_types.h b/pthread/sys/switch/phal_types.h new file mode 100644 index 00000000..6ec227aa --- /dev/null +++ b/pthread/sys/switch/phal_types.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct { + thread_h id; + void *stack; +} phal_tid; + +typedef struct { + _Atomic(uint32_t) lock; + uint32_t sem; +} phal_semaphore; diff --git a/pthread/tests/ChangeLog b/pthread/tests/ChangeLog new file mode 100644 index 00000000..6b2c7425 --- /dev/null +++ b/pthread/tests/ChangeLog @@ -0,0 +1,894 @@ +2005-06-12 Ross Johnson + + * stress1.c (millisecondsFromNow): Remove limit 0 <= millisecs < 1000; + now works for -INT_MAX <= millisecs <= INT_MAX; not needed for + stress1.c but should be general anyway. + +2005-05-18 Ross Johnson + + * reuse2.c (main): Must use a read with memory barrier semantics + when polling 'done' to force the cache into coherence on MP systems. + +2005-05-15 Ross Johnson + + * detach1.c: New test. + * join1.c: Reduce sleep times. + * join0.c: Remove MSVCRT conditional compile - join should always + return the thread exit code. + * join1.c: Likewise. + * join2.c: Likewise. + * join3.c: Likewise. + +2005-04-18 Ross Johnson + + * condvar3.c: Remove locks from around signalling calls - should not + be required for normal operation and only serve to mask deficiencies; + ensure that CV destruction is not premature after removing guards. + * condvar3_1.c: Likewise. + * condvar3_2.c: Likewise. + * condvar3_3.c: Likewise. + * condvar4.c: Likewise. + * condvar5.c: Likewise. + * condvar6.c: Likewise. + * condvar7.c: Likewise. + * condvar8.c: Likewise. + * condvar9.c: Likewise. + +2005-04-11 Ross Johnson + + * once4.c: New test; tries to test priority adjustments + in pthread_once(); set priority class to realtime so that + any failures can be seen. + +2005-04-06 Ross Johnson + + * cleanup0.c: Fix unguarded global variable accesses. + * cleanup1.c: Likewise. + * cleanup2.c: Likewise. + * cleanup3.c: Likewise. + * once2.c: Likewise. + * once3.c: Likewise. + +2005-04-01 Ross Johnson + + * GNUmakefile: Add target to test linking static link library. + * Makefile: Likewise. + * self1.c: Run process attach/detach routines when static linked. + +2005-03-16 Ross Johnson + + * mutex5.c: Prevent optimiser from removing asserts. + +2005-03-12 Ross Johnson + + * once3.c: New test. + +2005-03-08 Ross Johnson + + * once2.c: New test. + +2004-11-19 Ross Johnson + + * Bmakefile: New makefile for Borland. + * Makefile (DLL_VER): Added. + * GNUmakefile (DLL_VER): Added. + * Wmakefile (DLL_VER): Added. + +2004-10-29 Ross Johnson + + * semaphore4.c: New test. + * semaphore4t.c: New test. + * Debug.dsp (et al): Created MSVC Workspace project to aid debugging. + * All: Many tests have been modified to work with the new pthread + ID type; some other corrections were made after some library + functions were semantically strengthened. For example, + pthread_cond_destroy() no longer destroys a busy CV, which + required minor redesigns of some tests, including some where + the mutex associated with the CV was not locked during + signaling and broadcasting. + +2004-10-23 Ross Johnson + + * condvar3.c: Fixed mutex operations that were incorrectly + placed in relation to their condition variable operations. + The error became evident after sem_destroy() was rewritten + and conditions for destroing the semaphore were tightened. + As a result, pthread_cond_destroy() was not able to + destroy the cv queueing sempahore. + * condvar3_1.c: Likewise. + * condvar3_2.c: Likewise. + * condvar4.c: Likewise. + * condvar5.c: Likewise. + * condvar6.c: Likewise. + * condvar7.c: Likewise. + * condvar8.c: Likewise. + * condvar9.c: Likewise. + +2004-10-19 Ross Johnson + + * semaphore3.c: New test. + +2004-10-14 Ross Johnson + + * rwlock7.c (main): Tidy up statistics reporting; randomise + update accesses. + * rwlock8.c: New test. + +2004-09-08 Alexandre Girao + + * cancel7.c (main): Win98 wants a valid (non-NULL) location + for the last arg of _beginthreadex(). + * cancel8.c (main): Likewise. + * exit4.c (main): Likewise. + * exit5.c (main): Likewise. + +2004-08-26 Ross Johnson + + * create3.c: New test. + +2004-06-21 Ross Johnson + + * mutex2r.c: New test. + * mutex2e.c: New test. + * mutex3r.c: New test. + * mutex3e.c: New test. + * mutex6s.c: New test. + * mutex6rs.c: New test. + * mutex6es.c: New test. + +2004-05-21 Ross Johnson + + * join3.c: New test. + +2004-05-16 Ross Johnson + + * condvar2.c (WIN32_WINNT): Define to avoid redefinition warning + from inclusion of implement.h. + * convar2_1.c: Likewise. + * condvar3_1.c: Likewise. + * condvar3_2.c: Likewise. + * context1.c: Likewise. + * sizes.c: Likewise. + * Makefile: Don't define _WIN32_WINNT on compiler command line. + * GNUmakefile: Likewise. + * priority1.c (main): Add column to output for actual win32 + priority. + +2004-05-16 Ross Johnson + + * cancel9.c: New test. + * cancel3.c: Remove inappropriate conditional compilation; + GNU C version of test suite no longer quietly skips this test. + * cancel5.c: Likewise. + * GNUmakefile: Can now build individual test app using default + C version of library using 'make clean testname.c'. + * Makefile: Likewise for VC using 'nmake clean test testname.c'. + +2003-10-14 Ross Johnson + + * Wmakefile: New makefile for Watcom testing. + +2003-09-18 Ross Johnson + + * benchtest.h: Move old mutex code into benchlib.c. + * benchlib.c: New statically linked module to ensure that + bench apps don't inline the code and therefore have an unfair + advantage over the pthreads lib routines. Made little or no + difference. + * benchtest1.c: Minor change to avoid compiler warnings. + * benchtest5.c: Likewise. + * benchtest2.c: Fix misinformation in output report. + * README.BENCH: Add comments on results. + +2003-09-14 Ross Johnson + + * priority1.c: Reworked to comply with modified priority + management and provide additional output. + * priority2.c: Likewise. + * inherit1.c: Likewise. + +2003-09-03 Ross Johnson + + * exit4.c: New test. + * exit5.c: New test. + * cancel7.c: New test. + * cancel8.c: New test. + +2003-08-13 Ross Johnson + + * reuse1.c: New test. + * reuse1.c: New test. + * valid1.c: New test. + * valid2.c: New test. + * kill1.c: New test. + * create2.c: Now included in test regime. + +2003-07-19 Ross Johnson + + * eyal1.c (waste_time): Make threads do more work to ensure that + all threads get to do some work. + * semaphore1.c: Make it clear that certain errors are expected. + * exception2.c (non_MSVC code sections): Change to include + C++ standard include file, i.e. change to . + * exception3.c (non_MSVC code sections): Likewise; qualify std:: + namespace entities where necessary. + * GNUmakefile: modified to work in the MsysDTK (newer MinGW) + environment; define CC as gcc or g++ as appropriate because + using gcc -x c++ doesn't link with required c++ libs by default, + but g++ does. + +2002-12-11 Ross Johnson + + * mutex7e.c: Assert EBUSY return instead of EDEADLK. + +2002-06-03 Ross Johnson + + * semaphore2.c: New test. + +2002-03-02 Ross Johnson + + * Makefile (CFLAGS): Changed /MT to /MD to link with + the correct library MSVCRT.LIB. Otherwise errno doesn't + work. + +2002-02-28 Ross Johnson + + * exception3.c: Correct recent change. + + * semaphore1.c: New test. + + * Makefile: Add rule to generate pre-processor output. + +2002-02-28 Ross Johnson + + * exception3.c (terminateFunction): For MSVC++, call + exit() rather than pthread_exit(). Add comments to explain + why. + * Notes from the MSVC++ manual: + * 1) A term_func() should call exit(), otherwise + * abort() will be called on return to the caller. + * abort() raises SIGABRT. The default signal handler + * for all signals terminates the calling program with + * exit code 3. + * 2) A term_func() must not throw an exception. Therefore + * term_func() should not call pthread_exit() if an + * an exception-using version of pthreads-win32 library + * is being used (i.e. either pthreadVCE or pthreadVSE). + + +2002-02-23 Ross Johnson + + * rwlock2_t.c: New test. + * rwlock3_t.c: New test. + * rwlock4_t.c: New test. + * rwlock5_t.c: New test. + * rwlock6_t.c: New test. + * rwlock6_t2.c: New test. + * rwlock6.c (main): Swap thread and result variables + to correspond to actual thread functions. + * rwlock1.c: Change test description comment to correspond + to the actual test. + + * condvar1_2.c: Loop over the test many times in the hope + of detecting any intermittent deadlocks. This is to + test a fixed problem in pthread_cond_destroy.c. + + * spin4.c: Remove unused variable. + +2002-02-17 Ross Johnson + + * condvar1_1.c: New test. + * condvar1_2.c: New test. + +2002-02-07 Ross Johnson + + * delay1.c: New test. + * delay2.c: New test. + * exit4.c: New test. + +2002-02-02 Ross Johnson + + * mutex8: New test. + * mutex8n: New test. + * mutex8e: New test. + * mutex8r: New test. + * cancel6a: New test. + * cancel6d: New test. + * cleanup0.c: Add pragmas for inline optimisation control. + * cleanup1.c: Add pragmas for inline optimisation control. + * cleanup2.c: Add pragmas for inline optimisation control. + * cleanup3.c: Add pragmas for inline optimisation control. + * condvar7.c: Add pragmas for inline optimisation control. + * condvar8.c: Add pragmas for inline optimisation control. + * condvar9.c: Add pragmas for inline optimisation control. + +2002-01-30 Ross Johnson + + * cleanup1.c (): Must be declared __cdecl when compiled + as C++ AND testing the standard C library version. + +2002-01-16 Ross Johnson + + * spin4.c (main): Fix renamed function call. + +2002-01-14 Ross Johnson + + * exception3.c (main): Shorten wait time. + +2002-01-09 Ross Johnson + + * mutex7.c: New test. + * mutex7n.c: New test. + * mutex7e.c: New test. + * mutex7r.c: New test. + * mutex6.c: Modified to avoid leaving the locked mutex + around on exit. + +2001-10-25 Ross Johnson + + * condvar2.c: Remove reference to cv->nWaitersUnblocked. + * condvar2_1.c: Likewise; lower NUMTHREADS from 60 to 30. + * condvar3_1.c: Likewise. + * condvar3_2.c: Likewise. + * count1.c: lower NUMTHREADS from 60 to 30. + * inherit1.c: Determine valid priority values and then + assert values returned by POSIX routines are the same. + * priority1.c: Likewise. + * priority2.c: Likewise. + +2001-07-12 Ross Johnson + + * barrier5.c: Assert that precisely one thread receives + PTHREAD_BARRIER_SERIAL_THREAD at each barrier. + +2001-07-09 Ross Johnson + + * barrier3.c: Fixed. + * barrier4.c: Fixed. + * barrier5.c: New; proves that all threads in the group + reaching the barrier wait and then resume together. Repeats the test + using groups of 1 to 16 threads. Each group of threads must negotiate + a large number of barriers (10000). + * spin4.c: Fixed. + * test.h (error_string): Modified the success (0) value. + +2001-07-07 Ross Johnson + + * spin3.c: Changed test and fixed. + * spin4.c: Fixed. + * barrier3.c: Fixed. + * barrier4.c: Fixed. + +2001-07-05 Ross Johnson + + * spin1.c: New; testing spinlocks. + * spin2.c: New; testing spinlocks. + * spin3.c: New; testing spinlocks. + * spin4.c: New; testing spinlocks. + * barrier1.c: New; testing barriers. + * barrier2.c: New; testing barriers. + * barrier3.c: New; testing barriers. + * barrier4.c: New; testing barriers. + * GNUmakefile: Add new tests. + * Makefile: Add new tests. + +2001-07-01 Ross Johnson + + * benchtest3.c: New; timing mutexes. + * benchtest4.c: New; time mutexes. + * condvar3_1.c: Fixed bug - Alexander Terekhov + * condvar3_3.c: New test. + +2001-06-25 Ross Johnson + + * priority1.c: New test. + * priority2.c: New test. + * inherit1.c: New test. + * benchtest1.c: New; timing mutexes. + * benchtest2.c: New; timing mutexes. + * mutex4.c: Modified to test all mutex types. + +2001-06-8 Ross Johnson + + * mutex5.c: Insert inert change to quell compiler warnings. + * condvar3_2.c: Remove unused variable. + +2001-06-3 Ross Johnson + + * condvar2_1.c: New test. + * condvar3_1.c: New test. + * condvar3_2.c: New test. + +2001-05-30 Ross Johnson + + * mutex1n.c: New test. + * mutex1e.c: New test. + * mutex1r.c: New test. + * mutex4.c: Now locks and unlocks a mutex. + * mutex5.c: New test. + * mutex6.c: New test. + * mutex6n.c: New test. + * mutex6e.c: New test. + * mutex6r.c: New test. + * Makefile: Added new tests; reorganised. + * GNUmakefile: Likewise. + * rwlock6.c: Fix to properly prove read-while-write locking + and single writer locking. + +2001-05-29 Ross Johnson + + * Makefile: Reorganisation. + * GNUmakefile: Likewise. + - Thomas Pfaff + + * exception1.c: Add stdio.h include to define fprintf and stderr + in non-exception C version of main(). + * exception2.c: Likewise. + * exception3.c: Likewise. + + * Makefile (rwlock7): Add new test. + * GNUmakefile (rwlock7): Add new test. + * rwlock7.c: New test. + * rwlock6.c: Changed to test that writer has priority. + + * eyal1.c (main): Unlock each mutex_start lock before destroying + it. + +2000-12-29 Ross Johnson + + * GNUmakefile: Add mutex4 test; ensure libpthreadw32.a is + removed for "clean" target. + * Makefile: Add mutex4 test. + + * exception3.c: Remove SEH code; automatically pass the test + under SEH (which is an N/A environment). + + * mutex4.c: New test. + + * eyal1.c (do_work_unit): Add a dummy "if" to force the + optimiser to retain code; reduce thread work loads. + + * condvar8.c (main): Add an additional "assert" for debugging; + increase pthread_cond_signal timeout. + +2000-12-28 Ross Johnson + + * eyal1.c: Increase thread work loads. + * exception2.c: New test. + * exception3.c: New test. + * Makefile: Add new tests exception2.c and exception3.c. + * GNUmakefile: Likewise. + +2000-12-11 Ross Johnson + + * cleanup3.c: Remove unused variable. + * cleanup2.c: Likewise. + * exception1.c: Throw an exception rather than use + a deliberate zero divide so that catch(...) will + handle it under Mingw32. Mingw32 now builds the + library correctly to pass all tests - see Thomas + Pfaff's detailed instructions re needed changes + to Mingw32 in the Pthreads-Win32 FAQ. + +2000-09-08 Ross Johnson + + * cancel5.c: New; tests calling pthread_cancel() + from the main thread without first creating a + POSIX thread struct for the non-POSIX main thread + - this forces pthread_cancel() to create one via + pthread_self(). + * Makefile (cancel5): Add new test. + * GNUmakefile (cancel5): Likewise. + +2000-08-17 Ross Johnson + + * create2.c: New; Test that pthread_t contains + the W32 HANDLE before it calls the thread routine + proper. + +2000-08-13 Ross Johnson + + * condvar3.c: Minor change to eliminate compiler + warning. + + * condvar4.c: ditto. + + * condvar5.c: ditto. + + * condvar6.c: ditto. + + * condvar7.c: ditto. + + * condvar8.c: ditto. + + * condvar9.c: ditto. + + * exit1.c: Function needed return statement. + + * cleanup1.c: Remove unnecessary printf arg. + + * cleanup2.c: Fix cast. + + * rwlock6.c: Fix casts. + + * exception1.c (PtW32CatchAll): Had the wrong name; + fix casts. + + * cancel3.c: Remove unused waitLock variable. + + * GNUmakefile: Change library/dll naming; add new tests; + general minor changes. + + * Makefile: Change library/dll naming; add targets for + testing each of the two VC++ EH scheme versions; + default target now issues help message; compile warnings + now interpreted as errors to stop the make; add new + tests; restructure to remove prerequisites needed + otherwise. + + * README: Updated. + + +2000-08-10 Ross Johnson + + * eyal1.c (main): Change implicit cast to explicit + cast when passing "print_server" function pointer; + G++ no longer allows implicit func parameter casts. + + * cleanup1.c: Remove unused "waitLock". + (main): Fix implicit parameter cast. + + * cancel2.c (main): Fix implicit parameter cast. + + * cancel4.c (main): Fix implicit parameter cast. + + * cancel3.c (main): Fix implicit parameter cast. + + * GNUmakefile: Renamed from Makefile; Add missing + cancel1 and cancel2 test targets. + + * Makefile: Converted for use with MS nmake. + +2000-08-06 Ross Johnson + + * ccl.bat: Add /nologo to remove extraneous output. + + * exception1.c (exceptionedThread): Init 'dummy'; + put expression into if condition to prevent optimising away; + remove unused variable. + + * cancel4.c (mythread): Cast return value to avoid warnings. + + * cancel2.c (mythread): Missing #endif. + + * condvar9.c (mythread): Cast return value to avoid warnings. + + * condvar8.c (mythread): Cast return value to avoid warnings. + + * condvar7.c (mythread): Cast return value to avoid warnings. + + * cleanup3.c (mythread): Cast return value to avoid warnings. + + * cleanup2.c (mythread): Cast return value to avoid warnings. + + * cleanup1.c (mythread): Cast return value to avoid warnings. + + * condvar5.c (mythread): Cast return value to avoid warnings. + + * condvar3.c (mythread): Cast return value to avoid warnings. + + * condvar6.c (mythread): Cast return value to avoid warnings. + + * condvar4.c (mythread): Cast return value to avoid warnings. + +2000-08-05 Ross Johnson + + * cancel2.c: Use PtW32CatchAll macro if defined. + + * exception1.c: Use PtW32CatchAll macro if defined. + +2000-08-02 Ross Johnson + + * tsd1.c: Fix typecasts of &result [g++ is now very fussy]. + + * test.h (assert): Return 0's explicitly to allay + g++ errors. + + * join2.c: Add explicit typecasts. + + * join1.c: Add explicit typecasts. + + * join0.c: Add explicit typecasts. + + * eyal1.c: Add explicit typecasts. + + * count1.c (main): Add type cast to remove g++ parse warning + [gcc-2.95.2 seems to have tightened up on this]. + + * Makefile (GLANG): Use c++ explicitly. + Remove MSVC sections (was commented out). + Add target to generate cpp output. + +2000-07-25 Ross Johnson + + * runtest.bat: modified to work under W98. + + * runall.bat: Add new tests; modified to work under W98. + It was ok under NT. + + * Makefile: Add new tests. + + * exception1.c: New; Test passing exceptions back to the + application and retaining library internal exceptions. + + * join0.c: New; Test a single join. + +2000-01-06 Ross Johnson + + * cleanup1.c: New; Test cleanup handler executes (when thread is + canceled). + + * cleanup2.c: New; Test cleanup handler executes (when thread is + not canceled). + + * cleanup3.c: New; Test cleanup handler does not execute + (when thread is not canceled). + +2000-01-04 Ross Johnson + + * cancel4.c: New; Test cancelation does not occur in deferred + cancelation threads with no cancelation points. + + * cancel3.c: New; Test asynchronous cancelation. + + * context1.c: New; Test context switching method for async + cancelation. + +1999-11-23 Ross Johnson + + * test.h: Add header includes; include local header versions rather + than system versions; rearrange the assert macro defines. + +1999-11-07 Ross Johnson + + * loadfree.c: New. Test loading and freeing the library (DLL). + +1999-10-30 Ross Johnson + + * cancel1.c: New. Test pthread_setcancelstate and + pthread_setcanceltype functions. + * eyal1.c (waste_time): Change calculation to avoid FP exception + on Aplhas + - Rich Peters + +Oct 14 1999 Ross Johnson + + * condvar7.c: New. Test broadcast after waiting thread is canceled. + * condvar8.c: New. Test multiple broadcasts. + * condvar9.c: New. Test multiple broadcasts with thread + cancelation. + +Sep 16 1999 Ross Johnson + + * rwlock6.c: New test. + +Sep 15 1999 Ross Johnson + + * rwlock1.c: New test. + * rwlock2.c: New test. + * rwlock3.c: New test. + * rwlock4.c: New test. + * rwlock5.c: New test. + +Aug 22 1999 Ross Johnson + + * runall.bat (join2): Add test. + +Aug 19 1999 Ross Johnson + + * join2.c: New test. + +Wed Aug 12 1999 Ross Johnson + + * Makefile (LIBS): Add -L. + +Mon May 31 10:25:01 1999 Ross Johnson + + * Makefile (GLANG): Add GCC language option. + +Sat May 29 23:29:04 1999 Ross Johnson + + * runall.bat (condvar5): Add new test. + + * runall.bat (condvar6): Add new test. + + * Makefile (condvar5) : Add new test. + + * Makefile (condvar6) : Add new test. + + * condvar5.c: New test for pthread_cond_broadcast(). + + * condvar6.c: New test for pthread_cond_broadcast(). + +Sun Apr 4 12:04:28 1999 Ross Johnson + + * tsd1.c (mythread): Change Sleep(0) to sched_yield(). + (sched.h): Include. + + * condvar3.c (mythread): Remove redundant Sleep(). + + * runtest.bat: Re-organised to make more informative. + +Fri Mar 19 1999 Ross Johnson + + * *.bat: redirect unwanted output to nul: + + * runall.bat: new. + + * cancel1.c: new. Not part of suite yet. + +Mon Mar 15 00:17:55 1999 Ross Johnson + + * mutex1.c: only test mutex init and destroy; add assertions. + + * count1.c: raise number of spawned threads to 60 (appears to + be the limit under Win98). + +Sun Mar 14 21:31:02 1999 Ross Johnson + + * test.h (assert): add assertion trace option. + Use: + "#define ASSERT_TRACE 1" to turn it on, + "#define ASSERT_TRACE 0" to turn it off (default). + + * condvar3.c (main): add more assertions. + + * condvar4.c (main): add more assertions. + + * condvar1.c (main): add more assertions. + +Fri Mar 12 08:34:15 1999 Ross Johnson + + * condvar4.c (cvthing): switch the order of the INITIALIZERs. + + * eyal1.c (main): Fix trylock loop; was not waiting for thread to lock + the "started" mutex. + +Wed Mar 10 10:41:52 1999 Ross Johnson + + * tryentercs.c: Apply typo patch from bje. + + * tryentercs2.c: Ditto. + +Sun Mar 7 10:41:52 1999 Ross Johnson + + * Makefile (condvar3, condvar4): Add tests. + + * condvar4.c (General): Reduce to simple test case; prerequisite + is condvar3.c; add description. + + * condvar3.c (General): Reduce to simple test case; prerequisite + is condvar2.c; add description. + + * condvar2.c (General): Reduce to simple test case; prerequisite + is condvar1.c; add description. + + * condvar1.c (General): Reduce to simple test case; add + description. + + * Template.c (Comments): Add generic test detail. + +1999-02-23 Ross Johnson + + * Template.c: Revamp. + + * condvar1.c: Add. + + * condvar2.c: Add. + + * Makefile: Add condvar1 condvar2 tests. + + * exit1.c, exit2.c, exit3.c: Cosmetic changes. + +1999-02-23 Ross Johnson + + * Makefile: Some refinement. + + * *.c: More exhaustive checking through assertions; clean up; + add some more tests. + + * Makefile: Now actually runs the tests. + + * tests.h: Define our own assert macro. The Mingw32 + version pops up a dialog but we want to run non-interactively. + + * equal1.c: use assert a little more directly so that it + prints the actual call statement. + + * exit1.c: Modify to return 0 on success, 1 on failure. + +1999-02-22 Ross Johnson + + * self2.c: Bring up to date. + + * self3.c: Ditto. + +1999-02-21 Ben Elliston + + * README: Update. + + * Makefile: New file. Run all tests automatically. Primitive tests + are run first; more complex tests are run last. + + * count1.c: New test. Validate the thread count. + + * exit2.c: Perform a simpler test. + + * exit3.c: New test. Replaces exit2.c, since exit2.c needs to + perform simpler checking first. + + * create1.c: Update to use the new testsuite exiting convention. + + * equal1.c: Likewise. + + * mutex1.c: Likewise. + + * mutex2.c: Likewise. + + * once1.c: Likewise. + + * self2.c: Likewise. + + * self3.c: Likewise. + + * tsd1.c: Likewise. + +1999-02-20 Ross Johnson + + * mutex2.c: Test static mutex initialisation. + + * test.h: New. Declares a table mapping error numbers to + error names. + +1999-01-17 Ross Johnson + + * runtest: New script to build and run a test in the tests directory. + +Wed Dec 30 11:22:44 1998 Ross Johnson + + * tsd1.c: Re-written. See comments at start of file. + * Template.c: New. Contains skeleton code and comment template + intended to fully document the test. + +Fri Oct 16 17:59:49 1998 Ross Johnson + + * tsd1.c (destroy_key): Add function. Change diagnostics. + +Thu Oct 15 17:42:37 1998 Ross Johnson + + * tsd1.c (mythread): Fix some casts and add some message + output. Fix inverted conditional. + +Mon Oct 12 02:12:29 1998 Ross Johnson + + * tsd1.c: New. Test TSD using 1 key and 2 threads. + +1998-09-13 Ben Elliston + + * eyal1.c: New file; contributed by Eyal Lebedinsky + . + +1998-09-12 Ben Elliston + + * exit2.c (func): Return a value. + (main): Call the right thread entry function. + +1998-07-22 Ben Elliston + + * exit2.c (main): Fix size of pthread_t array. + +1998-07-10 Ben Elliston + + * exit2.c: New file; test pthread_exit() harder. + + * exit1.c: New file; test pthread_exit(). diff --git a/pthread/tests/Makefile b/pthread/tests/Makefile new file mode 100644 index 00000000..7919afa3 --- /dev/null +++ b/pthread/tests/Makefile @@ -0,0 +1,213 @@ +include $(LIBTRANSISTOR_HOME)/libtransistor.mk + +PROGRAM=pthread-test + +CLEANUP_TYPE=C +#CLEANUP_TYPE=CPP + +MUTEX_TEST_OBJS = \ + mutex1.o \ + mutex1e.o \ + mutex1n.o \ + mutex1r.o \ + mutex2.o \ + mutex2e.o \ + mutex2r.o \ + mutex3.o \ + mutex3e.o \ + mutex3r.o \ + mutex4.o \ + mutex5.o \ + mutex6.o \ + mutex6e.o \ + mutex6es.o \ + mutex6n.o \ + mutex6r.o \ + mutex6rs.o \ + mutex6s.o \ + mutex7.o \ + mutex7e.o \ + mutex7n.o \ + mutex7r.o \ + # Depends on unimplemented functions + #mutex8.o \ + #mutex8e.o \ + #mutex8n.o \ + #mutex8r.o + +MISC_OBJS = \ + main.o \ + test_main.o + + +MISC_TEST_OBJS = \ + valid1.o \ + valid2.o \ + self1.o \ + self2.o \ + equal1.o \ + count1.o \ + errno1.o \ + tsd1.o \ + tsd2.o \ + detach1.o +# Depends on non-portable functions +# delay1.o \ +# delay2.o \ +# Depends on unimplemented newlib functions +# stress1.o \ + +SEM_TEST_OBJS = \ + semaphore1.o \ + semaphore2.o \ + semaphore3.o \ + semaphore4.o \ + semaphore4t.o \ + semaphore5.o \ + semaphore6.o + +BARRIER_TEST_OBJS = \ + barrier1.o \ + barrier2.o \ + barrier3.o \ + barrier4.o \ + barrier5.o + +# Tests excluded because cancellation is not implemented +# semaphore4.o +# semaphore4t.o + +THREAD_TEST_OBJS = \ + create1.o \ + create2.o \ + create3.o \ + join0.o \ + join1.o \ + join2.o \ + join3.o \ + join4.o \ + kill1.o \ + exit1.o \ + exit2.o \ + exit3.o \ + exit4.o \ + exit5.o \ +# Depends on unimplemented HAL +# once1.o \ +# once2.o \ +# once3.o \ +# once4.o \ + +# PTE specific behavior: thread reuse +# reuse1.o \ +# reuse2.o \ + +# Not implemented yet +# priority1.o \ +# priority2.o \ +# inherit1.o + +SPIN_TEST_OBJS = \ + spin1.o \ + spin2.o \ + spin3.o \ +# Depends on ftime +# spin4.o + +CONDVAR_TEST_OBJS = \ + condvar1.o \ + condvar2.o \ + condvar2_1.o \ + condvar3.o \ + condvar3_1.o \ + condvar3_2.o \ + condvar3_3.o \ + condvar4.o \ + condvar5.o \ + condvar6.o \ + condvar7.o \ + condvar8.o \ + condvar9.o +# Needs NP method +# condvar1_1.o \ +# condvar1_2.o \ + +RWLOCK_TEST_OBJS = \ + rwlock1.o \ + rwlock2.o \ + rwlock2_t.o \ + rwlock3.o \ + rwlock3_t.o \ + rwlock4.o \ + rwlock4_t.o \ + rwlock5.o \ + rwlock5_t.o \ + rwlock6.o \ + rwlock6_t.o \ + rwlock6_t2.o \ + rwlock7.o \ + rwlock8.o + +CANCEL_TEST_OBJS = \ + cancel1.o \ + cancel2.o \ + cancel3.o \ + cancel4.o \ + cancel5.o \ + cancel6a.o \ + cancel6d.o \ + cleanup0.o \ + cleanup1.o \ + cleanup2.o \ + cleanup3.o + +BENCH_TEST_OBJS = \ + benchlib.o \ + benchtest1.o \ + benchtest2.o \ + benchtest3.o \ + benchtest4.o + +EXCEPTION_TEST_OBJS = \ + exception1.o \ + exception2.o \ + exception3.o + +OBJS = $(MUTEX_TEST_OBJS) $(MISC_OBJS) $(MISC_TEST_OBJS) $(THREAD_TEST_OBJS) $(SEM_TEST_OBJS) $(BARRIER_TEST_OBJS) $(SPIN_TEST_OBJS) $(CONDVAR_TEST_OBJS) $(RWLOCK_TEST_OBJS) $(CANCEL_TEST_OBJS) #$(BENCH_TEST_OBJS) $(EXCEPTION_TEST_OBJS) + +all: $(PROGRAM).nro + +CFLAGS += -I../ -I../sys/switch +$(PROGRAM).nro.so: ${OBJS} $(LIBTRANSITOR_NRO_LIB) $(LIBTRANSISTOR_COMMON_LIBS) + $(LD) $(LD_FLAGS) -o $@ ${OBJS} $(LIBTRANSISTOR_NRO_LDFLAGS) + +clean: + rm -f ${OBJS} $(PROGRAM).nro $(PROGRAM).nro.so + +#CFLAGS = $(GLOBAL_CFLAGS) -O2 -Wall -g -I.. -fno-strict-aliasing -I../.. -G0 +#CXXFLAGS = $(CFLAGS) -fexceptions -fno-rtti +#ASFLAGS = $(CFLAGS) + +#LDFLAGS = -L../.. +#LIBS = -lc -lpthread-psp -lstdc++ + +#ifeq ($(CLEANUP_TYPE),CPPXX) +# +#LIBS += -lstdc++ +# +#endif +# +#ifeq ($(CLEANUP_TYPE),CPPXXX) +# +#exception1.o: exception1.c +# $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(TARGET_ARCH) \ +# -c ../../tests/exception1.c -o exception1.o +# +#exception2.o: exception2.c +# $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(TARGET_ARCH) \ +# -c ../../tests/exception2.c -o exception2.o +# +#exception3.o: exception3.c +# $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDES) $(TARGET_ARCH) \ +# -c ../../tests/exception3.c -o exception3.o +#endif diff --git a/pthread/tests/README.md b/pthread/tests/README.md new file mode 100644 index 00000000..0a9c3261 --- /dev/null +++ b/pthread/tests/README.md @@ -0,0 +1 @@ +Tests shamelessly stolen from pthread-embedded, LGPL-Licensed. diff --git a/pthread/tests/barrier1.c b/pthread/tests/barrier1.c new file mode 100644 index 00000000..0538d06d --- /dev/null +++ b/pthread/tests/barrier1.c @@ -0,0 +1,63 @@ +/* + * barrier1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create a barrier object and then destroy it. + * + */ + +#include "test.h" + +static pthread_barrier_t barrier = NULL; + +int pthread_test_barrier1() +{ + assert(barrier == NULL); + + assert(pthread_barrier_init(&barrier, NULL, 1) == 0); + + assert(barrier != NULL); + + assert(pthread_barrier_destroy(&barrier) == 0); + + assert(barrier == NULL); + + return 0; +} diff --git a/pthread/tests/barrier2.c b/pthread/tests/barrier2.c new file mode 100644 index 00000000..86e7346b --- /dev/null +++ b/pthread/tests/barrier2.c @@ -0,0 +1,60 @@ +/* + * barrier2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a single barrier object, wait on it, + * and then destroy it. + * + */ + +#include "test.h" + +static pthread_barrier_t barrier = NULL; + +int pthread_test_barrier2() +{ + assert(pthread_barrier_init(&barrier, NULL, 1) == 0); + + assert(pthread_barrier_wait(&barrier) == PTHREAD_BARRIER_SERIAL_THREAD); + + assert(pthread_barrier_destroy(&barrier) == 0); + + return 0; +} diff --git a/pthread/tests/barrier3.c b/pthread/tests/barrier3.c new file mode 100644 index 00000000..1f16a796 --- /dev/null +++ b/pthread/tests/barrier3.c @@ -0,0 +1,77 @@ +/* + * barrier3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a single barrier object with barrier attribute, wait on it, + * and then destroy it. + * + */ + +#include "test.h" + +static pthread_barrier_t barrier = NULL; +static int result = 1; + +static void * func(void * arg) +{ + return (void *) pthread_barrier_wait(&barrier); +} + + +int pthread_test_barrier3() +{ + pthread_t t; + pthread_barrierattr_t ba; + + assert(pthread_barrierattr_init(&ba) == 0); + assert(pthread_barrierattr_setpshared(&ba, PTHREAD_PROCESS_PRIVATE) == 0); + assert(pthread_barrier_init(&barrier, &ba, 1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + + assert(result == PTHREAD_BARRIER_SERIAL_THREAD); + + assert(pthread_barrier_destroy(&barrier) == 0); + assert(pthread_barrierattr_destroy(&ba) == 0); + + return 0; +} diff --git a/pthread/tests/barrier4.c b/pthread/tests/barrier4.c new file mode 100644 index 00000000..43fc9833 --- /dev/null +++ b/pthread/tests/barrier4.c @@ -0,0 +1,119 @@ +/* + * barrier4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a single barrier object, multiple wait on it, + * and then destroy it. + * + */ + +#include "test.h" + +enum +{ + NUMTHREADS = 16 +}; + +static pthread_barrier_t barrier = NULL; +static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; +static int serialThreadCount = 0; +static int otherThreadCount = 0; + +static void * +func(void * arg) +{ + int result = pthread_barrier_wait(&barrier); + + assert(pthread_mutex_lock(&mx) == 0); + + if (result == PTHREAD_BARRIER_SERIAL_THREAD) + { + serialThreadCount++; + } + else if (0 == result) + { + otherThreadCount++; + } + else + { + return NULL; + } + assert(pthread_mutex_unlock(&mx) == 0); + + return NULL; +} + +int pthread_test_barrier4() +{ + int i, j; + pthread_t t[NUMTHREADS + 1]; + +// pthread_barrier_t barrier = NULL; +// serialThreadCount = 0; +// otherThreadCount = 0; + + mx = PTHREAD_MUTEX_INITIALIZER; + + for (j = 1; j <= NUMTHREADS; j++) + { + + serialThreadCount = 0; + + assert(pthread_barrier_init(&barrier, NULL, j) == 0); + + for (i = 1; i <= j; i++) + { + assert(pthread_create(&t[i], NULL, func, NULL) == 0); + } + + for (i = 1; i <= j; i++) + { + assert(pthread_join(t[i], NULL) == 0); + } + + assert(serialThreadCount == 1); + + assert(pthread_barrier_destroy(&barrier) == 0); + } + + assert(pthread_mutex_destroy(&mx) == 0); + + return 0; +} diff --git a/pthread/tests/barrier5.c b/pthread/tests/barrier5.c new file mode 100644 index 00000000..17e0fd51 --- /dev/null +++ b/pthread/tests/barrier5.c @@ -0,0 +1,133 @@ +/* + * barrier5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a single barrier object, set up a sequence of + * barrier points to prove lockstepness, and then destroy it. + * + */ + +#include "test.h" + +enum +{ + NUMTHREADS = 16, + BARRIERS = 1000 +}; + +static pthread_barrier_t barrier = NULL; +static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; + +static int barrierReleases[BARRIERS + 1]; + +static void * +func(void * barrierHeight) +{ + int i; + int result; + int serialThreads = 0; + + for (i = 1; i < BARRIERS; i++) + { + result = pthread_barrier_wait(&barrier); + + assert(pthread_mutex_lock(&mx) == 0); + barrierReleases[i]++; + assert(pthread_mutex_unlock(&mx) == 0); + /* + * Confirm the correct number of releases from the previous + * barrier. We can't do the current barrier yet because there may + * still be threads waking up. + */ + if (result == PTHREAD_BARRIER_SERIAL_THREAD) + { + serialThreads++; + assert(barrierReleases[i - 1] == (int) barrierHeight); + barrierReleases[i + 1] = 0; + } + else if (result != 0) + { + return NULL; + } + } + + return (void *) serialThreads; +} + +int pthread_test_barrier5() +{ + int i, j; + int result; + int serialThreadsTotal; + pthread_t t[NUMTHREADS + 1]; + + mx = PTHREAD_MUTEX_INITIALIZER; + + for (j = 1; j <= NUMTHREADS; j++) + { + + barrierReleases[0] = j; + barrierReleases[1] = 0; + + assert(pthread_barrier_init(&barrier, NULL, j) == 0); + + for (i = 1; i <= j; i++) + { + assert(pthread_create(&t[i], NULL, func, (void *) j) == 0); + } + + serialThreadsTotal = 0; + for (i = 1; i <= j; i++) + { + assert(pthread_join(t[i], (void **) &result) == 0); + serialThreadsTotal += result; + } + + assert(serialThreadsTotal == BARRIERS - 1); + assert(barrierReleases[BARRIERS - 1] == j); + assert(barrierReleases[BARRIERS] == 0); + + assert(pthread_barrier_destroy(&barrier) == 0); + } + + assert(pthread_mutex_destroy(&mx) == 0); + + return 0; +} diff --git a/pthread/tests/benchlib.c b/pthread/tests/benchlib.c new file mode 100644 index 00000000..469a8b55 --- /dev/null +++ b/pthread/tests/benchlib.c @@ -0,0 +1,75 @@ +/* + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include +#include +#include "pthread.h" +#include "sched.h" +#include "semaphore.h" +#include "benchtest.h" +#include "implement.h" + +void +dummy_call(int * a) +{ +} + +void +interlocked_inc_with_conditionals(int * a) +{ + if (a != NULL) + if (PTE_ATOMIC_INCREMENT(a) == -1) + { + *a = 0; + } +} + +void +interlocked_dec_with_conditionals(int * a) +{ + if (a != NULL) + if (PTE_ATOMIC_DECREMENT(a) == -1) + { + *a = 0; + } +} + + +/****************************************************************************************/ diff --git a/pthread/tests/benchtest.h b/pthread/tests/benchtest.h new file mode 100644 index 00000000..3e258c90 --- /dev/null +++ b/pthread/tests/benchtest.h @@ -0,0 +1,52 @@ +/* + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +//#include "../config.h" + +//extern BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION); +//extern HINSTANCE ptw32_h_kernel32; + +#define PTW32_OBJECT_AUTO_INIT ((void *) -1) + +void dummy_call(int * a); +void interlocked_inc_with_conditionals(int *a); +void interlocked_dec_with_conditionals(int *a); + +/****************************************************************************************/ diff --git a/pthread/tests/benchtest1.c b/pthread/tests/benchtest1.c new file mode 100644 index 00000000..8176e847 --- /dev/null +++ b/pthread/tests/benchtest1.c @@ -0,0 +1,226 @@ +/* + * benchtest1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Measure time taken to complete an elementary operation. + * + * - Mutex + * Single thread iteration over lock/unlock for each mutex type. + */ + +#include "test.h" +#include "implement.h" + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES +#define ITERATIONS 100000L + +static pthread_mutex_t mx; +static pthread_mutexattr_t ma; +static struct timeval currSysTimeStart; +static struct timeval currSysTimeStop; +static long durationMilliSecs; +static long overHeadMilliSecs = 0; +static int one = 1; +static int zero = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.tv_sec*1000+_TStop.tv_usec / 1000) \ + - (_TStart.tv_sec*1000+_TStart.tv_usec / 1000)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; gettimeofday(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++, NULL) { j++; + +#define TESTSTOP \ + }; gettimeofday(&currSysTimeStop); if (j + k == i, NULL) j++; } + + +static void +runTest (char * testNameString, int mType) +{ +#ifdef PTW32_MUTEX_TYPES + assert(pthread_mutexattr_settype(&ma, mType) == 0); +#endif + assert(pthread_mutex_init(&mx, &ma) == 0); + + TESTSTART + assert(pthread_mutex_lock(&mx) == zero); + assert(pthread_mutex_unlock(&mx) == zero); + TESTSTOP + + assert(pthread_mutex_destroy(&mx) == 0); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); +} + + +int pthread_test_bench1() +{ + int i = 0; + pte_osMutexHandle cs; + + overHeadMilliSecs = 0; + one = 1; + zero = 0; + + pthread_mutexattr_init(&ma); + + printf( "=============================================================================\n"); + printf( "\nLock plus unlock on an unlocked mutex.\n%ld iterations\n\n", + ITERATIONS); + printf( "%-45s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + TESTSTART + assert(1 == one); + assert(1 == one); + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + + TESTSTART + assert((dummy_call(&i), 1) == one); + assert((dummy_call(&i), 1) == one); + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + "Dummy call x 2", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + + TESTSTART + assert((interlocked_inc_with_conditionals(&i), 1) == one); + assert((interlocked_dec_with_conditionals(&i), 1) == one); + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + "Dummy call -> Interlocked with cond x 2", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + TESTSTART + assert((PTE_ATOMIC_INCREMENT(&i), 1) == one); + assert((PTE_ATOMIC_INCREMENT(&i), 1) == one); + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + "InterlockedOp x 2", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + + pte_osMutexCreate(&cs); + + TESTSTART + { + + pte_osMutexLock(cs); + pte_osMutexUnlock(cs); + } + TESTSTOP + + pte_osMutexDelete(cs); + + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + "Simple Critical Section", + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); + + + + printf( ".............................................................................\n"); + + /* + * Now we can start the actual tests + */ +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( "=============================================================================\n"); + + /* + * End of tests. + */ + + pthread_mutexattr_destroy(&ma); + + one = i; /* Dummy assignment to avoid 'variable unused' warning */ + return 0; +} diff --git a/pthread/tests/benchtest2.c b/pthread/tests/benchtest2.c new file mode 100644 index 00000000..16a9ddd5 --- /dev/null +++ b/pthread/tests/benchtest2.c @@ -0,0 +1,200 @@ +/* + * benchtest1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Measure time taken to complete an elementary operation. + * + * - Mutex + * Two threads iterate over lock/unlock for each mutex type. + * The two threads are forced into lock-step using two mutexes, + * forcing the threads to block on each lock operation. The + * time measured is therefore the worst case senario. + */ + +#include "test.h" + + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES +#define ITERATIONS 10000L + +static pthread_mutex_t gate1, gate2; +static pthread_mutexattr_t ma; +static long durationMilliSecs; +static long overHeadMilliSecs = 0; +static struct timeval currSysTimeStart; +static struct timeval currSysTimeStop; +static pthread_t worker; +static int running = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.tv_sec*1000+_TStop.tv_usec / 1000) \ + - (_TStart.tv_sec*1000+_TStart.tv_usec / 1000)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; gettimeofday(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++, NULL) { j++; + +#define TESTSTOP \ + }; gettimeofday(&currSysTimeStop); if (j + k == i, NULL) j++; } + + +static void * +overheadThread(void * arg) +{ + do + { + sched_yield(); + } + while (running); + + return NULL; +} + + +static void * +workerThread(void * arg) +{ + do + { + (void) pthread_mutex_lock(&gate1); + (void) pthread_mutex_lock(&gate2); + (void) pthread_mutex_unlock(&gate1); + sched_yield(); + (void) pthread_mutex_unlock(&gate2); + } + while (running); + + return NULL; +} + +static void +runTest (char * testNameString, int mType) +{ +#ifdef PTW32_MUTEX_TYPES + assert(pthread_mutexattr_settype(&ma, mType) == 0); +#endif + assert(pthread_mutex_init(&gate1, &ma) == 0); + assert(pthread_mutex_init(&gate2, &ma) == 0); + assert(pthread_mutex_lock(&gate1) == 0); + assert(pthread_mutex_lock(&gate2) == 0); + running = 1; + assert(pthread_create(&worker, NULL, workerThread, NULL) == 0); + TESTSTART + (void) pthread_mutex_unlock(&gate1); + sched_yield(); + (void) pthread_mutex_unlock(&gate2); + (void) pthread_mutex_lock(&gate1); + (void) pthread_mutex_lock(&gate2); + TESTSTOP + running = 0; + assert(pthread_mutex_unlock(&gate2) == 0); + assert(pthread_mutex_unlock(&gate1) == 0); + assert(pthread_join(worker, NULL) == 0); + assert(pthread_mutex_destroy(&gate2) == 0); + assert(pthread_mutex_destroy(&gate1) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + printf( "%-45s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS / 4 /* Four locks/unlocks per iteration */); +} + + +int pthread_test_bench2() +{ + assert(pthread_mutexattr_init(&ma) == 0); + + printf( "=============================================================================\n"); + printf( "\nLock plus unlock on a locked mutex.\n"); + printf("%ld iterations, four locks/unlocks per iteration.\n\n", ITERATIONS); + + printf( "%-45s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + running = 1; + assert(pthread_create(&worker, NULL, overheadThread, NULL) == 0); + TESTSTART + sched_yield(); + sched_yield(); + TESTSTOP + running = 0; + assert(pthread_join(worker, NULL) == 0); + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + + /* + * Now we can start the actual tests + */ +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Blocking locks", 0); +#endif + + printf( "=============================================================================\n"); + /* + * End of tests. + */ + + pthread_mutexattr_destroy(&ma); + + return 0; +} diff --git a/pthread/tests/benchtest3.c b/pthread/tests/benchtest3.c new file mode 100644 index 00000000..98acff94 --- /dev/null +++ b/pthread/tests/benchtest3.c @@ -0,0 +1,164 @@ +/* + * benchtest3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Measure time taken to complete an elementary operation. + * + * - Mutex + * Single thread iteration over a trylock on a locked mutex for each mutex type. + */ + +#include "test.h" + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES +#define ITERATIONS 100000L + +static pthread_mutex_t mx; +static pthread_mutexattr_t ma; +static struct timeval currSysTimeStart; +static struct timeval currSysTimeStop; +static long durationMilliSecs; +static long overHeadMilliSecs = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.tv_sec*1000+_TStop.tv_usec / 1000) \ + - (_TStart.tv_sec*1000+_TStart.tv_usec / 1000)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; gettimeofday(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++, NULL) { j++; + +#define TESTSTOP \ + }; gettimeofday(&currSysTimeStop); if (j + k == i, NULL) j++; } + + +static void * +trylockThread (void * arg) +{ + TESTSTART + (void) pthread_mutex_trylock(&mx); + TESTSTOP + + return NULL; +} + + +static void +runTest (char * testNameString, int mType) +{ + pthread_t t; + +#ifdef PTW32_MUTEX_TYPES + (void) pthread_mutexattr_settype(&ma, mType); +#endif + assert(pthread_mutex_init(&mx, &ma) == 0); + assert(pthread_mutex_lock(&mx) == 0); + assert(pthread_create(&t, NULL, trylockThread, 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_mutex_unlock(&mx) == 0); + assert(pthread_mutex_destroy(&mx) == 0); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); +} + + +int pthread_test_bench3() +{ + assert(pthread_mutexattr_init(&ma) == 0); + + printf( "=============================================================================\n"); + printf( "\nTrylock on a locked mutex.\n"); + printf( "%ld iterations.\n\n", ITERATIONS); + printf( "%-45s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + TESTSTART + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + + printf( ".............................................................................\n"); + + /* + * Now we can start the actual tests + */ +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( "=============================================================================\n"); + + /* + * End of tests. + */ + + pthread_mutexattr_destroy(&ma); + + return 0; +} diff --git a/pthread/tests/benchtest4.c b/pthread/tests/benchtest4.c new file mode 100644 index 00000000..d90a5ee8 --- /dev/null +++ b/pthread/tests/benchtest4.c @@ -0,0 +1,150 @@ +/* + * benchtest4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Measure time taken to complete an elementary operation. + * + * - Mutex + * Single thread iteration over trylock/unlock for each mutex type. + */ + +#include "test.h" + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define PTW32_MUTEX_TYPES +#define ITERATIONS 100000L + +static pthread_mutex_t mx; +static pthread_mutexattr_t ma; +static struct timeval currSysTimeStart; +static struct timeval currSysTimeStop; +static long durationMilliSecs; +static long overHeadMilliSecs = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.tv_sec*1000+_TStop.tv_usec / 1000) \ + - (_TStart.tv_sec*1000+_TStart.tv_usec / 1000)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; gettimeofday(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++, NULL) { j++; + +#define TESTSTOP \ + }; gettimeofday(&currSysTimeStop); if (j + k == i, NULL) j++; } + + +static void +runTest (char * testNameString, int mType) +{ +#ifdef PTW32_MUTEX_TYPES + pthread_mutexattr_settype(&ma, mType); +#endif + pthread_mutex_init(&mx, &ma); + + TESTSTART + (void) pthread_mutex_trylock(&mx); + (void) pthread_mutex_unlock(&mx); + TESTSTOP + + pthread_mutex_destroy(&mx); + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); +} + + +int pthread_test_bench4() +{ + pthread_mutexattr_init(&ma); + + printf( "=============================================================================\n"); + printf( "Trylock plus unlock on an unlocked mutex.\n"); + printf( "%ld iterations.\n\n", ITERATIONS); + printf( "%-45s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + TESTSTART + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + /* + * Now we can start the actual tests + */ +#ifdef PTW32_MUTEX_TYPES + runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT); + + runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL); + + runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK); + + runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE); +#else + runTest("Non-blocking lock", 0); +#endif + + printf( "=============================================================================\n"); + + /* + * End of tests. + */ + + pthread_mutexattr_destroy(&ma); + + return 0; +} diff --git a/pthread/tests/benchtest5.c b/pthread/tests/benchtest5.c new file mode 100644 index 00000000..3e404d66 --- /dev/null +++ b/pthread/tests/benchtest5.c @@ -0,0 +1,179 @@ +/* + * benchtest5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Measure time taken to complete an elementary operation. + * + * - Semaphore + * Single thread iteration over post/wait for a semaphore. + */ + +#include "test.h" + + +#ifdef __GNUC__ +#include +#endif + +#include "benchtest.h" + +#define ITERATIONS 1000000L + +sem_t sema; +//HANDLE w32sema; + +struct timeval currSysTimeStart; +struct timeval currSysTimeStop; +long durationMilliSecs; +long overHeadMilliSecs = 0; +int one = 1; +int zero = 0; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.tv_sec*1000+_TStop.tv_usec / 1000) \ + - (_TStart.tv_sec*1000+_TStart.tv_usec / 1000)) + +/* + * Dummy use of j, otherwise the loop may be removed by the optimiser + * when doing the overhead timing with an empty loop. + */ +#define TESTSTART \ + { int i, j = 0, k = 0; gettimeofday(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++, NULL) { j++; + +#define TESTSTOP \ + }; gettimeofday(&currSysTimeStop); if (j + k == i, NULL) j++; } + + +void +reportTest (char * testNameString) +{ + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + + printf( "%-45s %15ld %15.3f\n", + testNameString, + durationMilliSecs, + (float) durationMilliSecs * 1E3 / ITERATIONS); +} + + +int +main (int argc, char *argv[]) +{ + printf( "=============================================================================\n"); + printf( "\nOperations on a semaphore.\n%ld iterations\n\n", + ITERATIONS); + printf( "%-45s %15s %15s\n", + "Test", + "Total(msec)", + "average(usec)"); +<<<<<<< .mine +<<<<<<< .mine + * -------------------------------------------------------------------------- +======= + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * +======= + * -------------------------------------------------------------------------- +>>>>>>> .r47 +>>>>>>> .r51 + + /* + * Time the loop overhead so we can subtract it from the actual test times. + */ + + TESTSTART + assert(1 == one); + TESTSTOP + + durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; + overHeadMilliSecs = durationMilliSecs; + + + /* + * Now we can start the actual tests + */ + assert((w32sema = CreateSemaphore(NULL, (long) 0, (long) ITERATIONS, NULL)) != 0); + TESTSTART + assert(ReleaseSemaphore(w32sema, 1, NULL) != zero); + TESTSTOP + assert(CloseHandle(w32sema) != 0); + + reportTest("W32 Post with no waiters"); + + + assert((w32sema = CreateSemaphore(NULL, (long) ITERATIONS, (long) ITERATIONS, NULL)) != 0); + TESTSTART + assert(WaitForSingleObject(w32sema, INFINITE) == WAIT_OBJECT_0); + TESTSTOP + assert(CloseHandle(w32sema) != 0); + + reportTest("W32 Wait without blocking"); + + + assert(sem_init(&sema, 0, 0) == 0); + TESTSTART + assert(sem_post(&sema) == zero); + TESTSTOP + assert(sem_destroy(&sema) == 0); + + reportTest("POSIX Post with no waiters"); + + + assert(sem_init(&sema, 0, ITERATIONS) == 0); + TESTSTART + assert(sem_wait(&sema) == zero); + TESTSTOP + assert(sem_destroy(&sema) == 0); + + reportTest("POSIX Wait without blocking"); + + + printf( "=============================================================================\n"); + + /* + * End of tests. + */ + + return 0; +} diff --git a/pthread/tests/cancel1.c b/pthread/tests/cancel1.c new file mode 100644 index 00000000..4553091c --- /dev/null +++ b/pthread/tests/cancel1.c @@ -0,0 +1,188 @@ +/* + * File: cancel1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test setting cancel state and cancel type. + * - + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - pthread_setcancelstate function + * - pthread_setcanceltype function + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - pthread_create, pthread_self work. + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 2 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* ... */ + { + int oldstate; + + assert(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) == 0); + assert(oldstate == PTHREAD_CANCEL_ENABLE); /* Check default */ + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + assert(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) == 0); + assert(pthread_setcancelstate(oldstate, &oldstate) == 0); + assert(oldstate == PTHREAD_CANCEL_DISABLE); /* Check setting */ + + /* We don't support async cancellation so all of these tests would fail... */ +#if 0 + int oldtype; + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype) == 0); + assert(oldtype == PTHREAD_CANCEL_DEFERRED); /* Check default */ + assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + assert(pthread_setcanceltype(oldtype, &oldtype) == 0); + assert(oldtype == PTHREAD_CANCEL_ASYNCHRONOUS); /* Check setting */ +#endif //0 + + } + + return 0; +} + +int pthread_test_cancel1() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 1000); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + failed = !threadbag[i].started; + + if (failed) + { + fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); + } + } + + assert(!failed); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_join(t[i],NULL) == 0); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/cancel2.c b/pthread/tests/cancel2.c new file mode 100644 index 00000000..054df8ce --- /dev/null +++ b/pthread/tests/cancel2.c @@ -0,0 +1,237 @@ +/* + * File: cancel2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test SEH or C++ cancel exception handling within + * application exception blocks. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 1 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER; + +static void * +mythread(void * arg) +{ +// int result = 0; + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + switch (bag->threadnum % 2) + { + case 0: + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); +// result = 0; + break; + case 1: + assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); +// result = 1; + break; + } + +#if defined(__cplusplus) + try +#endif + { + /* Wait for go from main */ + assert(pthread_mutex_lock(&waitLock) == 0); + assert(pthread_mutex_unlock(&waitLock) == 0); + // TODO: sched_yield + phal_thread_sleep(0); + + for (;;) + { + pthread_testcancel(); + // TODO: sched_yield + phal_thread_sleep(0); + } + + } +#if defined(__cplusplus) + catch (...) + { + /* + * Should not get into here. + */ +// result += 100; + } +#endif + + /* + * Should not get to here either. + */ + return 0; +} + +int pthread_test_cancel2() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + waitLock = PTHREAD_MUTEX_INITIALIZER; + + assert((t[0] = pthread_self()) != NULL); + assert(pthread_mutex_lock(&waitLock) == 0); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + assert(pthread_mutex_unlock(&waitLock) == 0); + + phal_thread_sleep(500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_cancel(t[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + assert(pthread_join(t[i], (void **) &result) == 0); + fail = (result != (int) PTHREAD_CANCELED); + failed |= fail; + } + + assert(!failed); + + assert(pthread_mutex_destroy(&waitLock) == 0); + + /* + * Success. + */ + return 0; +} + + diff --git a/pthread/tests/cancel3.c b/pthread/tests/cancel3.c new file mode 100644 index 00000000..09426035 --- /dev/null +++ b/pthread/tests/cancel3.c @@ -0,0 +1,219 @@ +/* + * File: cancel3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test asynchronous cancelation (alertable or non-alertable). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - Async cancel if thread is not blocked (i.e. voluntarily resumes if blocked). + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join. + * - quserex.dll and alertdrv.sys are not available. + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static void * +mythread (void *arg) +{ + int result = ((int) PTHREAD_CANCELED + 1); + bag_t *bag = (bag_t *) arg; + + assert (bag == &threadbag[bag->threadnum]); + assert (bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + /* + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 100; bag->count++) + phal_thread_sleep (100); + + return (void *) result; +} + +int pthread_test_cancel3() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + assert ((t[0] = pthread_self ()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert (pthread_create (&t[i], NULL, mythread, (void *) &threadbag[i]) + == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep (500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert (pthread_cancel (t[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep (NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + fprintf (stderr, "Thread %d: started %d\n", i, + threadbag[i].started); + } + } + + assert (!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * The thread does not contain any cancelation points, so + * a return value of PTHREAD_CANCELED confirms that async + * cancelation succeeded. + */ + assert (pthread_join (t[i], (void **) &result) == 0); + + fail = (result != (int) PTHREAD_CANCELED); + + if (fail) + { + fprintf (stderr, "Thread %d: started %d: count %d\n", + i, threadbag[i].started, threadbag[i].count); + } + failed = (failed || fail); + } + + assert (!failed); + + /* + * Success. + */ + return 0; +} + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cancel3() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ diff --git a/pthread/tests/cancel4.c b/pthread/tests/cancel4.c new file mode 100644 index 00000000..2ccc9fc5 --- /dev/null +++ b/pthread/tests/cancel4.c @@ -0,0 +1,202 @@ +/* + * File: cancel4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test cancelation does not occur in deferred + * cancelation threads with no cancelation points. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - pthread_create + * pthread_self + * pthread_cancel + * pthread_join + * pthread_setcancelstate + * pthread_setcanceltype + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static void * +mythread(void * arg) +{ + int result = ((int)PTHREAD_CANCELED + 1); + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); + + /* + * We wait up to 2 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 20; bag->count++) + phal_thread_sleep(100); + + return (void *) result; +} + +int pthread_test_cancel4() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_cancel(t[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * The thread does not contain any cancelation points, so + * a return value of PTHREAD_CANCELED indicates that async + * cancelation occurred. + */ + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result == (int) PTHREAD_CANCELED); + + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/cancel5.c b/pthread/tests/cancel5.c new file mode 100644 index 00000000..dd1a154a --- /dev/null +++ b/pthread/tests/cancel5.c @@ -0,0 +1,210 @@ +/* + * File: cancel5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test calling pthread_cancel from the main thread + * without calling pthread_self() in main. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static void * +mythread (void *arg) +{ + int result = ((int) PTHREAD_CANCELED + 1); + bag_t *bag = (bag_t *) arg; + + assert (bag == &threadbag[bag->threadnum]); + assert (bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + /* + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 100; bag->count++) + phal_thread_sleep (100); + + return (void *) result; +} + +int pthread_test_cancel5() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert (pthread_create (&t[i], NULL, mythread, (void *) &threadbag[i]) + == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep (500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert (pthread_cancel (t[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep (NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert (!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * The thread does not contain any cancelation points, so + * a return value of PTHREAD_CANCELED confirms that async + * cancelation succeeded. + */ + assert (pthread_join (t[i], (void **) &result) == 0); + + fail = (result != (int) PTHREAD_CANCELED); + + failed = (failed || fail); + } + + assert (!failed); + + /* + * Success. + */ + return 0; +} + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cancel5() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ diff --git a/pthread/tests/cancel6a.c b/pthread/tests/cancel6a.c new file mode 100644 index 00000000..8c84a9bc --- /dev/null +++ b/pthread/tests/cancel6a.c @@ -0,0 +1,203 @@ +/* + * File: cancel6a.c + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 Ben Elliston and Ross Johnson + * Copyright (C) 1999,2000,2001 Ross Johnson + * + * Contact Email: rpj@ise.canberra.edu.au + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Test Synopsis: Test double cancelation - asynchronous. + * Second attempt should fail (ESRCH). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static void * +mythread(void * arg) +{ + int result = ((int)PTHREAD_CANCELED + 1); + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + /* + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 100; bag->count++) + phal_thread_sleep(100); + + return (void *) result; +} + +int pthread_test_cancel6a() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_cancel(t[i]) == 0); + assert(pthread_cancel(t[i]) == ESRCH); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * The thread does not contain any cancelation points, so + * a return value of PTHREAD_CANCELED confirms that async + * cancelation succeeded. + */ + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result != (int) PTHREAD_CANCELED); + + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cancel6a() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ diff --git a/pthread/tests/cancel6d.c b/pthread/tests/cancel6d.c new file mode 100644 index 00000000..010526ad --- /dev/null +++ b/pthread/tests/cancel6d.c @@ -0,0 +1,189 @@ +/* + * File: cancel6d.c + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 Ben Elliston and Ross Johnson + * Copyright (C) 1999,2000,2001 Ross Johnson + * + * Contact Email: rpj@ise.canberra.edu.au + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Test Synopsis: Test double cancelation - deferred. + * Second attempt should succeed (unless the canceled thread has started + * cancelation already - not tested here). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static void * +mythread(void * arg) +{ + int result = ((int)PTHREAD_CANCELED + 1); + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) == 0); + + /* + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 100; bag->count++) + { + phal_thread_sleep(100); + pthread_testcancel(); + } + + return (void *) result; +} + +int pthread_test_cancel6d() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_cancel(t[i]) == 0); + assert(pthread_cancel(t[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result != (int) PTHREAD_CANCELED); + + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/cleanup0.c b/pthread/tests/cleanup0.c new file mode 100644 index 00000000..14160bc1 --- /dev/null +++ b/pthread/tests/cleanup0.c @@ -0,0 +1,225 @@ +/* + * File: cleanup1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test cleanup handler executes (when thread is not canceled). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 10 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct + { + int i; + int null; + pte_osMutexHandle cs; + } sharedInt_t; + +static sharedInt_t pop_count = {0, 0}; + +static void +increment_pop_count(void * arg) +{ + sharedInt_t * sI = (sharedInt_t *) arg; + + pte_osMutexLock(sI->cs); + sI->i++; + pte_osMutexUnlock(sI->cs); +} + +static void * +mythread(void * arg) +{ + int result = 0; + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + pthread_cleanup_push(increment_pop_count, (void *) &pop_count); + + phal_thread_sleep(100); + + pthread_cleanup_pop(1); + + return (void *) result; +} + +int pthread_test_cleanup0() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + pte_osMutexCreate(&pop_count.cs); + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result == (int) PTHREAD_CANCELED); + + failed = (failed || fail); + } + + assert(!failed); + + assert(pop_count.i == NUMTHREADS); + + pte_osMutexDelete(pop_count.cs); + + /* + * Success. + */ + return 0; +} + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cleanup0() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ + diff --git a/pthread/tests/cleanup1.c b/pthread/tests/cleanup1.c new file mode 100644 index 00000000..303cc39f --- /dev/null +++ b/pthread/tests/cleanup1.c @@ -0,0 +1,240 @@ +/* + * File: cleanup1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test cleanup handler executes (when thread is canceled). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 10 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct + { + int i; + int null; + pte_osMutexHandle cs; + } sharedInt_t; + +static sharedInt_t pop_count = {0, 0}; + +static void +increment_pop_count(void * arg) +{ + sharedInt_t * sI = (sharedInt_t *) arg; + + pte_osMutexLock(sI->cs); + + sI->i++; + + pte_osMutexUnlock(sI->cs); + +} + +void * +mythread(void * arg) +{ + int result = 0; + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + pthread_cleanup_push(increment_pop_count, (void *) &pop_count); + /* + * We don't have true async cancelation - it relies on the thread + * at least re-entering the run state at some point. + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 100; bag->count++) + phal_thread_sleep(100); + + pthread_cleanup_pop(0); + + return (void *) result; +} + +int pthread_test_cleanup1() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + pte_osMutexCreate(&pop_count.cs); + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_cancel(t[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result != (int) PTHREAD_CANCELED); + + failed = (failed || fail); + } + + assert(!failed); + + assert(pop_count.i == NUMTHREADS); + + pte_osMutexDelete(pop_count.cs); + + /* + * Success. + */ + return 0; +} + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cleanup1() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ + diff --git a/pthread/tests/cleanup2.c b/pthread/tests/cleanup2.c new file mode 100644 index 00000000..4254304f --- /dev/null +++ b/pthread/tests/cleanup2.c @@ -0,0 +1,215 @@ +/* + * File: cleanup2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test cleanup handler executes (when thread is not canceled). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 10 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct + { + int i; + int null; + pte_osMutexHandle cs; + } sharedInt_t; + +static sharedInt_t pop_count = {0, 0}; + +static void +increment_pop_count(void * arg) +{ + sharedInt_t * sI = (sharedInt_t *) arg; + + pte_osMutexLock(sI->cs); + sI->i++; + pte_osMutexUnlock(sI->cs); +} + +static void * +mythread(void * arg) +{ + int result = 0; + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + pthread_cleanup_push(increment_pop_count, (void *) &pop_count); + + sched_yield(); + + pthread_cleanup_pop(1); + + return (void *) result; +} + +int pthread_test_cleanup2() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + pte_osMutexCreate(&pop_count.cs); + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(1000); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result != 0); + + failed = (failed || fail); + } + + assert(!failed); + + assert(pop_count.i == NUMTHREADS); + + pte_osMutexDelete(pop_count.cs); + + /* + * Success. + */ + return 0; +} + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cleanup2() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ + diff --git a/pthread/tests/cleanup3.c b/pthread/tests/cleanup3.c new file mode 100644 index 00000000..02574fd2 --- /dev/null +++ b/pthread/tests/cleanup3.c @@ -0,0 +1,226 @@ +/* + * File: cleanup3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test cleanup handler does not execute (when thread is + * not canceled). + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + + +#include "test.h" + +#ifdef PTE_SUPPORT_ASYNC_CANCEL + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 10 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct + { + int i; + int null; + pte_osMutexHandle cs; + } sharedInt_t; + +static sharedInt_t pop_count = {0, 0}; + +static void +increment_pop_count(void * arg) +{ + sharedInt_t * sI = (sharedInt_t *) arg; + + pte_osMutexLock(sI->cs); + + sI->i++; + + pte_osMutexUnlock(sI->cs); + +} + +static void * +mythread(void * arg) +{ + int result = 0; + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + pthread_cleanup_push(increment_pop_count, (void *) &pop_count); + + sched_yield(); + + pte_osMutexLock(pop_count.cs); + + pop_count.i--; + + pte_osMutexUnlock(pop_count.cs); + + + pthread_cleanup_pop(0); + + return (void *) result; +} + +int pthread_test_cleanup3() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + pte_osMutexCreate(&pop_count.cs); + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(1000); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result != 0); + + failed = (failed || fail); + } + + assert(!failed); + + assert(pop_count.i == -(NUMTHREADS)); + + pte_osMutexDelete(pop_count.cs); + + /* + * Success. + */ + return 0; +} + + +#else /* PTE_SUPPORT_ASYNC_CANCEL */ + +int pthread_test_cleanup3() +{ + printf("Test not run - async cancellation not supported\n"); + + return 0; +} + +#endif /* !PTE_SUPPORT_ASYNC_CANCEL */ diff --git a/pthread/tests/condvar1.c b/pthread/tests/condvar1.c new file mode 100644 index 00000000..37eb3757 --- /dev/null +++ b/pthread/tests/condvar1.c @@ -0,0 +1,104 @@ +/* + * File: condvar1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test initialisation and destruction of a CV. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Creates and then imediately destroys a CV. Does not + * test the CV. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_init returns 0, and + * - pthread_cond_destroy returns 0. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_init returns non-zero, or + * - pthread_cond_destroy returns non-zero. + * - Process returns non-zero exit status. + */ + +#include "test.h" + +static pthread_cond_t cv = NULL; + +int pthread_test_condvar1() +{ + cv = NULL; + + assert(cv == NULL); + + assert(pthread_cond_init(&cv, NULL) == 0); + + assert(cv != NULL); + + assert(pthread_cond_destroy(&cv) == 0); + + assert(cv == NULL); + + return 0; +} diff --git a/pthread/tests/condvar1_1.c b/pthread/tests/condvar1_1.c new file mode 100644 index 00000000..11eace66 --- /dev/null +++ b/pthread/tests/condvar1_1.c @@ -0,0 +1,122 @@ +/* + * File: condvar1_1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test CV linked list management. + * + * Test Method (Validation or Falsification): + * - Validation: + * Initiate and destroy several CVs in random order. + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Creates and then imediately destroys a CV. Does not + * test the CV. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - All initialised CVs destroyed without segfault. + * - Successfully broadcasts all remaining CVs after + * each CV is removed. + * + * Fail Criteria: + */ + +#include +#include "test.h" + +enum +{ + NUM_CV = 10 +}; + +static pthread_cond_t cv[NUM_CV]; + +int pthread_test_condvar1_1() +{ + int i, j; + + for (i = 0; i < NUM_CV; i++) + { + /* Traverse the list before every init of a CV. */ + assert(pthread_timechange_handler_np(NULL) == (void *) 0); + assert(pthread_cond_init(&cv[i], NULL) == 0); + } + + j = NUM_CV; + (void) srand((unsigned)time(NULL)); + + do + { + i = rand() % NUM_CV; + + if (cv[i] != NULL) + { + j--; + assert(pthread_cond_destroy(&cv[i]) == 0); + /* Traverse the list every time we remove a CV. */ + assert(pthread_timechange_handler_np(NULL) == (void *) 0); + } + } + while (j > 0); + + return 0; +} diff --git a/pthread/tests/condvar1_2.c b/pthread/tests/condvar1_2.c new file mode 100644 index 00000000..670478d8 --- /dev/null +++ b/pthread/tests/condvar1_2.c @@ -0,0 +1,130 @@ +/* + * File: condvar1_2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test CV linked list management and serialisation. + * + * Test Method (Validation or Falsification): + * - Validation: + * Initiate and destroy several CVs in random order. + * Asynchronously traverse the CV list and broadcast. + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Creates and then imediately destroys a CV. Does not + * test the CV. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - All initialised CVs destroyed without segfault. + * - Successfully broadcasts all remaining CVs after + * each CV is removed. + * + * Fail Criteria: + */ + +#include +#include "test.h" + +enum +{ + NUM_CV = 5, + NUM_LOOPS = 5 +}; + +static pthread_cond_t cv[NUM_CV]; + +int pthread_test_condvar1_2() +{ + int i, j, k; + int result = -1; + pthread_t t; + + for (k = 0; k < NUM_LOOPS; k++) + { + for (i = 0; i < NUM_CV; i++) + { + assert(pthread_cond_init(&cv[i], NULL) == 0); + } + + j = NUM_CV; + (void) srand((unsigned)time(NULL)); + + /* Traverse the list asynchronously. */ + assert(pthread_create(&t, NULL, pthread_timechange_handler_np, NULL) == 0); + + do + { + i = rand() % NUM_CV; + if (cv[i] != NULL) + { + j--; + assert(pthread_cond_destroy(&cv[i]) == 0); + } + } + while (j > 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert (result == 0); + } + + return 0; +} diff --git a/pthread/tests/condvar2.c b/pthread/tests/condvar2.c new file mode 100644 index 00000000..75a8d728 --- /dev/null +++ b/pthread/tests/condvar2.c @@ -0,0 +1,127 @@ +/* + * File: condvar2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test timed wait on a CV. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Because the CV is never signaled, we expect the wait to time out. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait does not return ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#define _WIN32_WINNT 0x400 + +#include "test.h" + + +static pthread_cond_t cv; +static pthread_mutex_t mutex; + +int pthread_test_condvar2() +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + assert(pthread_cond_init(&cv, NULL) == 0); + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + + assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT); + + assert(pthread_mutex_unlock(&mutex) == 0); + + { + int result = pthread_cond_destroy(&cv); + + assert(result == 0); + } + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/condvar2_1.c b/pthread/tests/condvar2_1.c new file mode 100644 index 00000000..51e21c6f --- /dev/null +++ b/pthread/tests/condvar2_1.c @@ -0,0 +1,152 @@ +/* + * File: condvar2_1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test timeout of multiple waits on a CV with no signal/broadcast. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Because the CV is never signaled, we expect the waits to time out. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait does not return ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#define _WIN32_WINNT 0x400 + +#include "test.h" + + +static pthread_cond_t cv; +static pthread_mutex_t mutex; +static struct timespec abstime = + { + 0, 0 + }; + +enum +{ + NUMTHREADS = 16 // OS_MAX_SIMUL_THREADS +}; + +static void * +mythread(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT); + + assert(pthread_mutex_unlock(&mutex) == 0); + + return arg; +} + +int pthread_test_condvar2_1() +{ + int i; + pthread_t t[NUMTHREADS + 1]; + int result = 0; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + assert(pthread_cond_init(&cv, NULL) == 0); + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + assert(pthread_mutex_lock(&mutex) == 0); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); + } + + assert(pthread_mutex_unlock(&mutex) == 0); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_join(t[i], (void **) &result) == 0); + + assert(result == i); + } + + assert(pthread_cond_destroy(&cv) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/condvar3.c b/pthread/tests/condvar3.c new file mode 100644 index 00000000..0a164ab8 --- /dev/null +++ b/pthread/tests/condvar3.c @@ -0,0 +1,152 @@ +/* + * File: condvar3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test basic function of a CV + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - The primary thread takes the lock before creating any threads. + * The secondary thread blocks on the lock allowing the primary + * thread to enter the cv wait state which releases the lock. + * The secondary thread then takes the lock and signals the waiting + * primary thread. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns 0. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +static pthread_cond_t cv; +static pthread_mutex_t mutex; +static int shared = 0; + +enum +{ + NUMTHREADS = 2 /* Including the primary thread. */ +}; + +static void * +mythread(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + shared++; + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_cond_signal(&cv) == 0); + + return (void *) 0; +} + +int pthread_test_condvar3() +{ + pthread_t t[NUMTHREADS]; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + assert((t[0] = pthread_self()) != NULL); + + assert(pthread_cond_init(&cv, NULL) == 0); + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); + + abstime.tv_sec += 5; + + while (! (shared > 0)) + assert_eq(pthread_cond_timedwait(&cv, &mutex, &abstime), 0); + + assert(shared > 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_join(t[1], NULL) == 0); + + assert(pthread_cond_destroy(&cv) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/condvar3_1.c b/pthread/tests/condvar3_1.c new file mode 100644 index 00000000..f4bb68df --- /dev/null +++ b/pthread/tests/condvar3_1.c @@ -0,0 +1,204 @@ +/* + * File: condvar3_1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test timeout of multiple waits on a CV with some signaled. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Because some CVs are never signaled, we expect their waits to time out. + * Some are signaled, the rest time out. Pthread_cond_destroy() will fail + * unless all are accounted for, either signaled or timedout. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait does not return ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#define _WIN32_WINNT 0x400 + +#include "test.h" + + +static pthread_cond_t cv; +static pthread_cond_t cv1; +static pthread_mutex_t mutex; +static pthread_mutex_t mutex1; +static struct timespec abstime = + { + 0, 0 + }; +static int timedout = 0; +static int signaled = 0; +static int awoken = 0; +static int waiting = 0; + +enum +{ + NUMTHREADS = 30 +}; + +static void * +mythread(void * arg) +{ + int result; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + assert(pthread_mutex_lock(&mutex1) == 0); + ++waiting; + assert(pthread_mutex_unlock(&mutex1) == 0); + assert(pthread_cond_signal(&cv1) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + result = pthread_cond_timedwait(&cv, &mutex, &abstime); + if (result == ETIMEDOUT) + { + timedout++; + } + else + { + awoken++; + } + assert(pthread_mutex_unlock(&mutex) == 0); + + return arg; +} + +int pthread_test_condvar3_1() +{ + int i; + pthread_t t[NUMTHREADS + 1]; + int result = 0; + + timedout = 0; + signaled = 0; + awoken = 0; + waiting = 0; + + + assert(pthread_cond_init(&cv, NULL) == 0); + assert(pthread_cond_init(&cv1, NULL) == 0); + + assert(pthread_mutex_init(&mutex, NULL) == 0); + assert(pthread_mutex_init(&mutex1, NULL) == 0); + + assert(pthread_mutex_lock(&mutex1) == 0); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); + } + + do + { + assert(pthread_cond_wait(&cv1,&mutex1) == 0); + } + while ( NUMTHREADS > waiting ); + + assert(pthread_mutex_unlock(&mutex1) == 0); + + for (i = NUMTHREADS/3; i <= 2*NUMTHREADS/3; i++) + { +// assert(pthread_mutex_lock(&mutex) == 0); + assert(pthread_cond_signal(&cv) == 0); +// assert(pthread_mutex_unlock(&mutex) == 0); + + signaled++; + } + + for (i = 1; i <= NUMTHREADS; i++) + { + assert_eq(pthread_join(t[i], (void **) &result), 0); + assert_eq(result, i); + } + + assert_eq(awoken, signaled); + assert_eq(timedout, NUMTHREADS - signaled); + + assert(pthread_cond_destroy(&cv1) == 0); + + { + assert(pthread_cond_destroy(&cv) == 0); + } + + assert(pthread_mutex_destroy(&mutex1) == 0); + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/condvar3_2.c b/pthread/tests/condvar3_2.c new file mode 100644 index 00000000..68f4cfa0 --- /dev/null +++ b/pthread/tests/condvar3_2.c @@ -0,0 +1,199 @@ +/* + * File: condvar3_2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test timeout of multiple waits on a CV with remainder broadcast awoken. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Because some CVs are never signaled, we expect their waits to time out. + * Some time out, the rest are broadcast signaled. Pthread_cond_destroy() will fail + * unless all are accounted for, either signaled or timedout. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait does not return ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#define _WIN32_WINNT 0x400 + +#include "test.h" +#include +#include + +static pthread_cond_t cv; +static pthread_mutex_t mutex; +static struct timespec abstime = + { + 0, 0 + }; +static struct timespec abstime2 = + { + 0, 0 + }; +static _Atomic(int) timedout = 0; +static _Atomic(int) awoken = 0; + +enum +{ + NUMTHREADS = 16 //OS_MAX_SIMUL_THREADS +}; + +static void * +mythread(void * arg) +{ + int result; + + assert(pthread_mutex_lock(&mutex) == 0); + + abstime2.tv_sec = abstime.tv_sec; + + if ((int) arg % 3 == 0) + { + abstime2.tv_sec += 2; + } + + result = pthread_cond_timedwait(&cv, &mutex, &abstime2); + assert(pthread_mutex_unlock(&mutex) == 0); + if (result == ETIMEDOUT) + { + timedout++; + } + else + { + awoken++; + } + + + return arg; +} + +int pthread_test_condvar3_2() +{ + int i; + pthread_t t[NUMTHREADS + 1]; + int result = 0; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + timedout = 0; + awoken = 0; + + + assert(pthread_cond_init(&cv, NULL) == 0); + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = abstime.tv_sec = currSysTime.tv_sec + 5; + abstime.tv_nsec = abstime2.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + assert(pthread_mutex_lock(&mutex) == 0); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0); + } + + assert(pthread_mutex_unlock(&mutex) == 0); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_join(t[i], (void **) &result) == 0); + assert(result == i); + /* + * Approximately 2/3rds of the threads are expected to time out. + * Signal the remainder after some threads have woken up and exited + * and while some are still waking up after timeout. + * Also tests that redundant broadcasts don't return errors. + */ + +// assert(pthread_mutex_lock(&mutex) == 0); + + if (atomic_fetch_add(&awoken, 0L) > NUMTHREADS/3) + { + assert(pthread_cond_broadcast(&cv) == 0); + } + +// assert(pthread_mutex_unlock(&mutex) == 0); + + } + + assert(awoken == NUMTHREADS - timedout); + + { + assert(pthread_cond_destroy(&cv) == 0); + } + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/condvar3_3.c b/pthread/tests/condvar3_3.c new file mode 100644 index 00000000..f4f0d939 --- /dev/null +++ b/pthread/tests/condvar3_3.c @@ -0,0 +1,145 @@ +/* + * File: condvar3_3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test timeouts and lost signals on a CV. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait does not return ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +/* Timur Aydin (taydin@snet.net) */ + +#include "test.h" + + +static pthread_cond_t cnd; +static pthread_mutex_t mtx; + +int pthread_test_condvar3_3() +{ + int rc; + + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + assert(pthread_cond_init(&cnd, 0) == 0); + assert(pthread_mutex_init(&mtx, 0) == 0); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + abstime.tv_sec += 1; + + /* Here pthread_cond_timedwait should time out after one second. */ + + assert(pthread_mutex_lock(&mtx) == 0); + + assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT); + + // Stop some compilers from reporting that rc is not used + rc = rc; + + assert(pthread_mutex_unlock(&mtx) == 0); + + /* Here, the condition variable is signaled, but there are no + threads waiting on it. The signal should be lost and + the next pthread_cond_timedwait should time out too. */ + +// assert(pthread_mutex_lock(&mtx) == 0); + + assert((rc = pthread_cond_signal(&cnd)) == 0); +// assert(pthread_mutex_unlock(&mtx) == 0); + + assert(pthread_mutex_lock(&mtx) == 0); + + gettimeofday(&currSysTime, NULL); + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + abstime.tv_sec += 1; + + assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT); + assert(pthread_mutex_unlock(&mtx) == 0); + + assert(pthread_cond_destroy(&cnd) == 0); + assert(pthread_mutex_destroy(&mtx) == 0); + + return 0; +} diff --git a/pthread/tests/condvar4.c b/pthread/tests/condvar4.c new file mode 100644 index 00000000..8ed766aa --- /dev/null +++ b/pthread/tests/condvar4.c @@ -0,0 +1,181 @@ +/* + * File: condvar4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test PTHREAD_COND_INITIALIZER. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Test basic CV function but starting with a static initialised + * CV. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns 0. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#include "test.h" + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ + { + pthread_cond_t notbusy; + pthread_mutex_t lock; + int shared; + }; + +static cvthing_t cvthing = +{ + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +enum +{ + NUMTHREADS = 2 +}; + +static void * +mythread(void * arg) +{ + assert(pthread_mutex_lock(&cvthing.lock) == 0); + cvthing.shared++; + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_cond_signal(&cvthing.notbusy) == 0); + + return (void *) 0; +} + +int pthread_test_condvar4() +{ + pthread_t t[NUMTHREADS]; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + cvthing.shared = 0; + + cvthing.notbusy = PTHREAD_COND_INITIALIZER; + cvthing.lock = PTHREAD_MUTEX_INITIALIZER; + + + assert((t[0] = pthread_self()) != NULL); + + assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + + assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + + assert(cvthing.lock != PTHREAD_MUTEX_INITIALIZER); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT); + assert(cvthing.notbusy != PTHREAD_COND_INITIALIZER); + + assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + while (! (cvthing.shared > 0)) + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + + assert(cvthing.shared > 0); + + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_join(t[1], NULL) == 0); + assert(pthread_mutex_destroy(&cvthing.lock) == 0); + + assert(cvthing.lock == NULL); + + assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + + assert(cvthing.notbusy == NULL); + + return 0; +} diff --git a/pthread/tests/condvar5.c b/pthread/tests/condvar5.c new file mode 100644 index 00000000..95e7ff61 --- /dev/null +++ b/pthread/tests/condvar5.c @@ -0,0 +1,182 @@ +/* + * File: condvar5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test pthread_cond_broadcast. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Test broadcast with one waiting CV. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - pthread_cond_timedwait returns 0. + * - Process returns zero exit status. + * + * Fail Criteria: + * - pthread_cond_timedwait returns ETIMEDOUT. + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ + { + pthread_cond_t notbusy; + pthread_mutex_t lock; + int shared; + }; + +static cvthing_t cvthing = +{ + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +enum +{ + NUMTHREADS = 2 +}; + +static void * +mythread(void * arg) +{ + assert(pthread_mutex_lock(&cvthing.lock) == 0); + cvthing.shared++; + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + + return (void *) 0; +} + +int pthread_test_condvar5() +{ + pthread_t t[NUMTHREADS]; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + cvthing.notbusy = PTHREAD_COND_INITIALIZER; + cvthing.lock = PTHREAD_MUTEX_INITIALIZER; + + cvthing.shared = 0; + + assert((t[0] = pthread_self()) != NULL); + + assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + + assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + + assert(cvthing.lock != PTHREAD_MUTEX_INITIALIZER); + + /* get current system time */ + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT); + + assert(cvthing.notbusy != PTHREAD_COND_INITIALIZER); + + assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0); + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + while (! (cvthing.shared > 0)) + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + + assert(cvthing.shared > 0); + + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_join(t[1], NULL) == 0); + + assert(pthread_mutex_destroy(&cvthing.lock) == 0); + + assert(cvthing.lock == NULL); + + assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + + assert(cvthing.notbusy == NULL); + + return 0; +} diff --git a/pthread/tests/condvar6.c b/pthread/tests/condvar6.c new file mode 100644 index 00000000..326d8bdc --- /dev/null +++ b/pthread/tests/condvar6.c @@ -0,0 +1,260 @@ + +/* + * File: condvar6.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test pthread_cond_broadcast. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Test broadcast with NUMTHREADS (=5) waiting CVs. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 5 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ + { + pthread_cond_t notbusy; + pthread_mutex_t lock; + int shared; + }; + +static cvthing_t cvthing = +{ + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = + { + 0, 0 + }; + +static int awoken; + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Wait for the start gun */ + assert(pthread_mutex_lock(&start_flag) == 0); + assert(pthread_mutex_unlock(&start_flag) == 0); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + + while (! (cvthing.shared > 0)) + { + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + assert_eq(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime), 0); + } + + assert(cvthing.shared > 0); + + awoken++; + + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + return (void *) 0; +} + +int pthread_test_condvar6() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + + start_flag = PTHREAD_MUTEX_INITIALIZER; + cvthing.notbusy = PTHREAD_COND_INITIALIZER; + cvthing.lock = PTHREAD_MUTEX_INITIALIZER; + + cvthing.shared = 0; + + assert((t[0] = pthread_self()) != NULL); + + assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + + assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&start_flag) == 0); + + + + assert((t[0] = pthread_self()) != NULL); + + awoken = 0; + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + + assert(pthread_mutex_unlock(&start_flag) == 0); + + /* + * Give threads time to start. + */ + phal_thread_sleep(1000); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + cvthing.shared++; + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + + /* + * Give threads time to complete. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_join(t[i], NULL) == 0); + } + + /* + * Cleanup the CV. + */ + + assert(pthread_mutex_destroy(&cvthing.lock) == 0); + + assert(cvthing.lock == NULL); + + assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + + assert(cvthing.notbusy == NULL); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + failed = !threadbag[i].started; + } + + assert(!failed); + + /* + * Check any results here. + */ + + assert(awoken == NUMTHREADS); + + assert(pthread_mutex_destroy(&start_flag) == 0); + + /* + * Success. + */ + return 0; +} + + diff --git a/pthread/tests/condvar7.c b/pthread/tests/condvar7.c new file mode 100644 index 00000000..a255bacd --- /dev/null +++ b/pthread/tests/condvar7.c @@ -0,0 +1,263 @@ +/* + * File: condvar7.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test pthread_cond_broadcast with thread cancelation. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Test broadcast with NUMTHREADS (=5) waiting CVs, one is canceled while waiting. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 5 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ + { + pthread_cond_t notbusy; + pthread_mutex_t lock; + int shared; + }; + +static cvthing_t cvthing = +{ + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = + { + 0, 0 + }; + +static int awoken; + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Wait for the start gun */ + assert(pthread_mutex_lock(&start_flag) == 0); + assert(pthread_mutex_unlock(&start_flag) == 0); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + + pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); + + while (! (cvthing.shared > 0)) + { + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + } + + pthread_cleanup_pop(0); + + assert(cvthing.shared > 0); + + awoken++; + + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + return (void *) 0; +} + +int pthread_test_condvar7() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + cvthing.notbusy = PTHREAD_COND_INITIALIZER; + cvthing.lock = PTHREAD_MUTEX_INITIALIZER; + + cvthing.shared = 0; + + assert((t[0] = pthread_self()) != NULL); + + assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + + assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&start_flag) == 0); + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 10; + + assert((t[0] = pthread_self()) != NULL); + + awoken = 0; + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + + assert(pthread_mutex_unlock(&start_flag) == 0); + + /* + * Give threads time to start. + */ + phal_thread_sleep(1000); + + /* + * Cancel one of the threads. + */ + assert(pthread_cancel(t[1]) == 0); + assert(pthread_join(t[1], NULL) == 0); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + cvthing.shared++; + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + /* + * Signal all remaining waiting threads. + */ + assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + + /* + * Wait for all threads to complete. + */ + for (i = 2; i <= NUMTHREADS; i++) + assert(pthread_join(t[i], NULL) == 0); + + /* + * Cleanup the CV. + */ + + assert(pthread_mutex_destroy(&cvthing.lock) == 0); + + assert(cvthing.lock == NULL); + + assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + + assert(cvthing.notbusy == NULL); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + failed = !threadbag[i].started; + } + + assert(!failed); + + /* + * Check any results here. + */ + + assert(awoken == (NUMTHREADS - 1)); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/condvar8.c b/pthread/tests/condvar8.c new file mode 100644 index 00000000..7aa4e867 --- /dev/null +++ b/pthread/tests/condvar8.c @@ -0,0 +1,265 @@ +/* + * File: condvar8.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test multiple pthread_cond_broadcasts. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Make NUMTHREADS threads wait on CV, broadcast signal them, and then repeat. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 5 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ + { + pthread_cond_t notbusy; + pthread_mutex_t lock; + int shared; + }; + +static cvthing_t cvthing = +{ + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = + { + 0, 0 + }; + +static int awoken; + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Wait for the start gun */ + assert(pthread_mutex_lock(&start_flag) == 0); + assert(pthread_mutex_unlock(&start_flag) == 0); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + + pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); + + while (! (cvthing.shared > 0)) + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + + pthread_cleanup_pop(0); + + assert(cvthing.shared > 0); + + awoken++; + + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + return (void *) 0; +} + +int pthread_test_condvar8() +{ + int failed = 0; + int i; + int first, last; + pthread_t t[NUMTHREADS + 1]; + + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + cvthing.notbusy = PTHREAD_COND_INITIALIZER; + cvthing.lock = PTHREAD_MUTEX_INITIALIZER; + start_flag = PTHREAD_MUTEX_INITIALIZER; + + assert((t[0] = pthread_self()) != NULL); + + assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + + assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 10; + + assert((t[0] = pthread_self()) != NULL); + + awoken = 0; + + for (first = 1, last = NUMTHREADS / 2; + first < NUMTHREADS; + first = last + 1, last = NUMTHREADS) + { + assert(pthread_mutex_lock(&start_flag) == 0); + + for (i = first; i <= last; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + cvthing.shared = 0; + + assert(pthread_mutex_unlock(&start_flag) == 0); + + /* + * Give threads time to start. + */ + phal_thread_sleep(100); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + cvthing.shared++; + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + + /* + * Give threads time to complete. + */ + for (i = first; i <= last; i++) + { + assert(pthread_join(t[i], NULL) == 0); + } + + assert(awoken == (i - 1)); + } + + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + failed = !threadbag[i].started; + } + + /* + * Cleanup the CV. + */ + + assert(pthread_mutex_destroy(&cvthing.lock) == 0); + + assert(cvthing.lock == NULL); + + assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + + assert(cvthing.notbusy == NULL); + + assert(!failed); + + /* + * Check any results here. + */ + + assert(awoken == NUMTHREADS); + + assert(pthread_mutex_destroy(&start_flag) == 0); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/condvar9.c b/pthread/tests/condvar9.c new file mode 100644 index 00000000..8ca50bad --- /dev/null +++ b/pthread/tests/condvar9.c @@ -0,0 +1,271 @@ +/* + * File: condvar9.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test multiple pthread_cond_broadcasts with thread cancelation. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - Make NUMTHREADS threads wait on CV, cancel one, broadcast signal them, + * and then repeat. + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 9 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + int finished; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +typedef struct cvthing_t_ cvthing_t; + +struct cvthing_t_ + { + pthread_cond_t notbusy; + pthread_mutex_t lock; + int shared; + }; + +static cvthing_t cvthing = +{ + PTHREAD_COND_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + 0 +}; + +static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER; + +static struct timespec abstime = + { + 0, 0 + }; + +static int awoken; + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Wait for the start gun */ + assert(pthread_mutex_lock(&start_flag) == 0); + assert(pthread_mutex_unlock(&start_flag) == 0); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + + /* + * pthread_cond_timedwait is a cancelation point and we're + * going to cancel some threads deliberately. + */ + pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); + + while (! (cvthing.shared > 0)) + assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0); + + pthread_cleanup_pop(0); + + assert(cvthing.shared > 0); + + awoken++; + bag->finished = 1; + + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + return (void *) 0; +} + +int pthread_test_condvar9() +{ + int failed = 0; + int i; + int first, last; + int canceledThreads = 0; + pthread_t t[NUMTHREADS + 1]; + + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + cvthing.notbusy = PTHREAD_COND_INITIALIZER; + cvthing.lock = PTHREAD_MUTEX_INITIALIZER; + + assert((t[0] = pthread_self()) != NULL); + + assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER); + + assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER); + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + + assert((t[0] = pthread_self()) != NULL); + + awoken = 0; + + for (first = 1, last = NUMTHREADS / 2; + first < NUMTHREADS; + first = last + 1, last = NUMTHREADS) + { + int ct; + + assert(pthread_mutex_lock(&start_flag) == 0); + + for (i = first; i <= last; i++) + { + threadbag[i].started = threadbag[i].finished = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + cvthing.shared = 0; + + assert(pthread_mutex_unlock(&start_flag) == 0); + + /* + * Give threads time to start. + */ + phal_thread_sleep(1000); + + ct = (first + last) / 2; + assert(pthread_cancel(t[ct]) == 0); + canceledThreads++; + assert(pthread_join(t[ct], NULL) == 0); + + assert(pthread_mutex_lock(&cvthing.lock) == 0); + cvthing.shared++; + assert(pthread_mutex_unlock(&cvthing.lock) == 0); + + assert(pthread_cond_broadcast(&cvthing.notbusy) == 0); + + /* + * Standard check that all threads started - and wait for them to finish. + */ + for (i = first; i <= last; i++) + { + failed = !threadbag[i].started; + + if (!failed) + { + assert(pthread_join(t[i], NULL) == 0 || threadbag[i].finished == 0); + } + } + } + + /* + * Cleanup the CV. + */ + + assert(pthread_mutex_destroy(&cvthing.lock) == 0); + + assert(cvthing.lock == NULL); + + assert(pthread_cond_destroy(&cvthing.notbusy) == 0); + + assert(cvthing.notbusy == NULL); + + assert(!failed); + + /* + * Check any results here. + */ + + assert(awoken == NUMTHREADS - canceledThreads); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/count1.c b/pthread/tests/count1.c new file mode 100644 index 00000000..494937da --- /dev/null +++ b/pthread/tests/count1.c @@ -0,0 +1,106 @@ +/* + * count1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Description: + * Test some basic assertions about the number of threads at runtime. + */ + +#include +#include + +#include "test.h" + +//#define NUMTHREADS OS_MAX_SIMUL_THREADS +#define NUMTHREADS 16 + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_t threads[NUMTHREADS]; +static unsigned numThreads = 0; + +static void * +myfunc(void *arg) +{ + pthread_mutex_lock(&lock); + numThreads++; + pthread_mutex_unlock(&lock); + + phal_thread_sleep(1000); + return 0; +} + +int pthread_test_count1() +{ + int i; + int maxThreads = sizeof(threads) / sizeof(pthread_t); + + numThreads = 0; + + lock = PTHREAD_MUTEX_INITIALIZER; + + /* + * Spawn NUMTHREADS threads. Each thread should increment the + * numThreads variable, sleep for one second. + */ + for (i = 0; i < maxThreads; i++) + { + assert(pthread_create(&threads[i], NULL, myfunc, 0) == 0); + } + + /* + * Wait for all the threads to exit. + */ + for (i = 0; i < maxThreads; i++) + { + assert(pthread_join(threads[i], NULL) == 0); + } + + /* + * Check the number of threads created. + */ + assert((int) numThreads == maxThreads); + + assert(pthread_mutex_destroy(&lock) == 0); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/create1.c b/pthread/tests/create1.c new file mode 100644 index 00000000..3071d27d --- /dev/null +++ b/pthread/tests/create1.c @@ -0,0 +1,77 @@ +/* + * create1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Description: + * Create a thread and check that it ran. + * + * Depends on API functions: None. + */ + +#include + +#include "test.h" + +static int washere = 0; + +static void * func(void * arg) +{ + washere = 1; + return 0; +} + +int pthread_test_create1() +{ + pthread_t t; + + washere = 0; + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + /* A dirty hack, but we cannot rely on pthread_join in this + primitive test. */ + phal_thread_sleep(2 * 1000); + + assert(washere == 1); + + assert(pthread_join(t,NULL) == 0); + + return 0; +} diff --git a/pthread/tests/create2.c b/pthread/tests/create2.c new file mode 100644 index 00000000..03342a0b --- /dev/null +++ b/pthread/tests/create2.c @@ -0,0 +1,117 @@ +/* + * File: create2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test that threads have a Win32 handle when started. + * + * Test Method (Validation or Falsification): + * - Statistical, not absolute (depends on sample size). + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +enum +{ + NUMTHREADS = 100 +}; + +static volatile int washere = 0; + +static void * func(void * arg) +{ +// washere = 1; + washere++; + return (void *) 0; +} + +int pthread_test_create2() +{ + pthread_t t; + pthread_attr_t attr; + void * result = NULL; + int i; + + washere = 0; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + for (i = 0; i < NUMTHREADS; i++) + { + washere = 0; + assert(pthread_create(&t, &attr, func, NULL) == 0); + pthread_join(t, &result); + assert(washere == 1); + } + + return 0; +} diff --git a/pthread/tests/create3.c b/pthread/tests/create3.c new file mode 100644 index 00000000..c5a1379a --- /dev/null +++ b/pthread/tests/create3.c @@ -0,0 +1,127 @@ +/* + * File: create3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2003 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test passing NULL as thread id arg to pthread_create. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + + +#ifdef __GNUC__ +#include +#endif + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 10 +}; + + +static void * +threadFunc(void * arg) +{ + return (void *) 0; +} + +int pthread_test_create3() +{ + int i; + pthread_t mt; + pthread_t t[NUMTHREADS]; + + assert((mt = pthread_self()) != NULL); + + /* Avoid compiler warning */ + mt = mt; + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&t[i], NULL, threadFunc, NULL) == 0); + } + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_join(t[i],NULL) == 0); + } + + /* + * Success. + */ + return 0; +} + diff --git a/pthread/tests/delay1.c b/pthread/tests/delay1.c new file mode 100644 index 00000000..f5e3b04f --- /dev/null +++ b/pthread/tests/delay1.c @@ -0,0 +1,61 @@ +/* + * delay1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: + * pthread_delay_np + */ + +#include "test.h" + +int pthread_test_delay1() +{ + struct timespec interval = + { + 1L, 500000000L + }; + + pthread_delay_np(&interval); + + assert(pthread_delay_np(&interval) == 0); + + return 0; +} + diff --git a/pthread/tests/delay2.c b/pthread/tests/delay2.c new file mode 100644 index 00000000..5eebb415 --- /dev/null +++ b/pthread/tests/delay2.c @@ -0,0 +1,88 @@ +/* + * delay1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: + * pthread_delay_np + */ + +#include "test.h" + +pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; + +static void * +func(void * arg) +{ + struct timespec interval = + { + 5, 500000000L + }; + + assert(pthread_mutex_lock(&mx) == 0); + + pthread_cleanup_push(pthread_mutex_unlock, &mx); + assert(pthread_delay_np(&interval) == 0); + pthread_cleanup_pop(1); + + return (void *) 1; +} + +int pthread_test_delay2() +{ + pthread_t t; + int result = 0; + + mx = PTHREAD_MUTEX_INITIALIZER; + + assert(pthread_mutex_lock(&mx) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + assert(pthread_cancel(t) == 0); + + assert(pthread_mutex_unlock(&mx) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == (int) PTHREAD_CANCELED); + + assert(pthread_mutex_destroy(&mx) == 0); + + return 0; +} + diff --git a/pthread/tests/detach1.c b/pthread/tests/detach1.c new file mode 100644 index 00000000..77582e93 --- /dev/null +++ b/pthread/tests/detach1.c @@ -0,0 +1,104 @@ +/* + * Test for pthread_detach(). + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: pthread_create(), pthread_detach(), pthread_exit(). + */ + +#include "test.h" + + +enum +{ + NUMTHREADS = 20 +}; + +static void * +func(void * arg) +{ + int i = (int) arg; + + phal_thread_sleep(i * 10); + + pthread_exit(arg); + + /* Never reached. */ + exit(1); + + /* Just to avoid compiler warnings */ + return NULL; +} + +int pthread_test_detach1() +{ + pthread_t id[NUMTHREADS]; + int i; + + /* Create a few threads and then exit. */ + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); + } + + + /* Some threads will finish before they are detached, some after. */ + phal_thread_sleep(NUMTHREADS/2 * 10 + 50); + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_detach(id[i]) == 0); + } + + phal_thread_sleep(NUMTHREADS * 10 + 1000); + + /* + * Check that all threads are now invalid. + * This relies on unique thread IDs - e.g. works with + * pthreads-w32 or Solaris, but may not work for Linux, BSD etc. + */ + for (i = 0; i < NUMTHREADS; i++) + { + // TODO: Add a way to check if a thread is still valid + //assert(pthread_kill(id[i], 0) == ESRCH); + } + + /* Success. */ + return 0; +} diff --git a/pthread/tests/equal1.c b/pthread/tests/equal1.c new file mode 100644 index 00000000..9220b2fa --- /dev/null +++ b/pthread/tests/equal1.c @@ -0,0 +1,70 @@ +/* + * Test for pthread_equal. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on functions: pthread_create(). + */ + +#include "test.h" + +static void * func(void * arg) +{ + phal_thread_sleep(2000); + return 0; +} + +int pthread_test_equal1() +{ + pthread_t t1, t2; + + assert(pthread_create(&t1, NULL, func, (void *) 1) == 0); + + assert(pthread_create(&t2, NULL, func, (void *) 2) == 0); + + assert(pthread_equal(t1, t2) == 0); + + assert(pthread_equal(t1,t1) != 0); + + assert(pthread_join(t1,NULL) == 0); + assert(pthread_join(t2,NULL) == 0); + + /* Success. */ + return 0; +} diff --git a/pthread/tests/errno1.c b/pthread/tests/errno1.c new file mode 100644 index 00000000..20c4c621 --- /dev/null +++ b/pthread/tests/errno1.c @@ -0,0 +1,179 @@ +/* + * File: errno1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test thread-safety of errno + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 3 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static pthread_mutex_t stop_here = PTHREAD_MUTEX_INITIALIZER; + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + errno = bag->threadnum; + + phal_thread_sleep(1000); + + pthread_mutex_lock(&stop_here); + + assert(errno == bag->threadnum); + + pthread_mutex_unlock(&stop_here); + + phal_thread_sleep(1000); + + return 0; +} + +int pthread_test_errno1() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + pthread_mutex_lock(&stop_here); + errno = 0; + + assert((t[0] = pthread_self()) != NULL); + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(2000); + pthread_mutex_unlock(&stop_here); + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 1000); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + failed = !threadbag[i].started; + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print ouput on failure. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + /* ... */ + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} diff --git a/pthread/tests/exception1.c b/pthread/tests/exception1.c new file mode 100644 index 00000000..044382c8 --- /dev/null +++ b/pthread/tests/exception1.c @@ -0,0 +1,221 @@ +/* + * File: exception1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test passing of exceptions back to the application. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + + + +#include "test.h" + +#if defined(__cplusplus) && defined(PTE_SUPPORT_ASYNC_CANCEL) + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { + NUMTHREADS = 4 +}; + +static void * +exceptionedThread(void * arg) +{ + int dummy = 0; + int result = ((int)PTHREAD_CANCELED + 1); + /* Set to async cancelable */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + phal_thread_sleep(100); + + try + { + /* + * I had a zero divide exception here but it + * wasn't being caught by the catch(...) + * below under Mingw32. That could be a problem. + */ + throw dummy; + } + catch (...) + { + /* Should get into here. */ + result = ((int)PTHREAD_CANCELED + 2); + } + + return (void *) result; +} + +static void * +canceledThread(void * arg) +{ + int result = ((int)PTHREAD_CANCELED + 1); + int count; + + + /* Set to async cancelable */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + try + { + /* + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (count = 0; count < 100; count++) + phal_thread_sleep(100); + } + catch (...) + { + /* Should NOT get into here. */ + result = ((int)PTHREAD_CANCELED + 2); + } + + return (void *) result; +} + + +int +pthread_test_exception1() +{ + int failed = 0; + int i; + pthread_t mt; + pthread_t et[NUMTHREADS]; + pthread_t ct[NUMTHREADS]; + + assert((mt = pthread_self()) != NULL); + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&et[i], NULL, exceptionedThread, (void *) 0) == 0); + assert(pthread_create(&ct[i], NULL, canceledThread, NULL) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(1000); + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_cancel(ct[i]) == 0); + } + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 1000); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 0; i < NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* Canceled thread */ + assert(pthread_join(ct[i], (void **) &result) == 0); + assert(!(fail = (result != (int) PTHREAD_CANCELED))); + + failed = (failed || fail); + + /* Exceptioned thread */ + assert(pthread_join(et[i], (void **) &result) == 0); + assert(!(fail = (result != ((int) PTHREAD_CANCELED + 2)))); + + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} + +#else + +int +pthread_test_exception1() +{ + printf("Test N/A for this compiler environment.\n"); + return 0; +} + +#endif diff --git a/pthread/tests/exception2.c b/pthread/tests/exception2.c new file mode 100644 index 00000000..05dda3ca --- /dev/null +++ b/pthread/tests/exception2.c @@ -0,0 +1,150 @@ +/* + * File: exception2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test passing of exceptions out of thread scope. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + + +#if defined(__cplusplus) + +#include +#include + +#ifdef __GNUC__ +#include +#endif + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { + NUMTHREADS = 1 +}; + +static void * +exceptionedThread(void * arg) +{ + int dummy = 0x1; + + throw dummy; + + return (void *) 100; +} + + +int +pthread_test_exception2() +{ + int i; + pthread_t mt; + pthread_t et[NUMTHREADS]; + + std::set_terminate(0); + + /* + if (argc <= 1) + { + int result; + + printf("You should see an \"abnormal termination\" message\n"); + fflush(stdout); + result = system("exception2.exe die"); + exit(0); + } + */ + assert((mt = pthread_self()) != NULL); + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0); + } + + phal_thread_sleep(1000); + + /* + * Success. + */ + return 0; +} + +#else /* defined(__cplusplus) */ + +#include + +int +pthread_test_exception2() +{ + printf("Test N/A for this compiler environment.\n"); + return 0; +} + +#endif /* defined(__cplusplus) */ diff --git a/pthread/tests/exception3.c b/pthread/tests/exception3.c new file mode 100644 index 00000000..079e0dd9 --- /dev/null +++ b/pthread/tests/exception3.c @@ -0,0 +1,161 @@ +/* + * File: exception3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test running of user supplied terminate() function. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#if defined(__cplusplus) + +# if defined(__GNUC__) && __GNUC__ < 3 +# include +# else +# include + using std::set_terminate; +# endif + + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { + NUMTHREADS = 1 +}; + +int caught = 0; +pthread_mutex_t caughtLock; + + + +static void +terminateFunction () +{ + assert(pthread_mutex_lock(&caughtLock) == 0); + caught++; + assert(pthread_mutex_unlock(&caughtLock) == 0); + + pthread_exit((void *) 0); +} + +static void * +exceptionedThread(void * arg) +{ + int dummy = 0x1; + + (void) set_terminate(&terminateFunction); + + throw dummy; + + return (void *) 0; +} + +int +pthread_test_exception3() +{ + int i; + pthread_t mt; + pthread_t et[NUMTHREADS]; + pthread_mutexattr_t ma; + + assert((mt = pthread_self()) != NULL); + + assert(pthread_mutexattr_init(&ma) == 0); + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&caughtLock, &ma) == 0); + assert(pthread_mutexattr_destroy(&ma) == 0); + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0); + } + + phal_thread_sleep(1000); + + assert(caught == NUMTHREADS); + + /* + * Success. + */ + return 0; +} + +#else /* defined(__cplusplus) */ + +#include + +int +pthread_test_exception3() +{ + printf("Test N/A for this compiler environment.\n"); + return 0; +} + +#endif /* defined(__cplusplus) */ diff --git a/pthread/tests/exit1.c b/pthread/tests/exit1.c new file mode 100644 index 00000000..77425635 --- /dev/null +++ b/pthread/tests/exit1.c @@ -0,0 +1,69 @@ +/* + * Test for pthread_exit(). + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: None. + */ + +#include "test.h" + +static void * func(void * param) +{ + pthread_exit((void *) 0); + + /* Not reached */ + assert(0); + +} + +int pthread_test_exit1() +{ + pthread_t id; + /* A simple test first. */ + + assert(pthread_create(&id, NULL, func, 0) == 0); + + // Don't want to depend on join. + phal_thread_sleep(1000); + + assert(pthread_join(id,NULL) == 0); + + return 0; +} diff --git a/pthread/tests/exit2.c b/pthread/tests/exit2.c new file mode 100644 index 00000000..fdc44147 --- /dev/null +++ b/pthread/tests/exit2.c @@ -0,0 +1,71 @@ +/* + * Test for pthread_exit(). + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: + * pthread_create() + * pthread_exit() + */ + +#include "test.h" + +static void * +func(void * arg) +{ + pthread_exit(arg); + + /* Never reached. */ + assert(0); + + return NULL; +} + +int pthread_test_exit2() +{ + pthread_t t; + + assert(pthread_create(&t, NULL, func, (void *) NULL) == 0); + + phal_thread_sleep(1000); + + assert(pthread_join(t,NULL) == 0); + + return 0; +} diff --git a/pthread/tests/exit3.c b/pthread/tests/exit3.c new file mode 100644 index 00000000..54771e79 --- /dev/null +++ b/pthread/tests/exit3.c @@ -0,0 +1,80 @@ +/* + * Test for pthread_exit(). + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: pthread_create(). + */ + +#include "test.h" + +static void * +func(void * arg) +{ + pthread_exit(arg); + + /* Never reached. */ + assert(0); + + return NULL; +} + +int pthread_test_exit3() +{ + pthread_t id[4]; + int i; + + /* Create a few threads and then exit. */ + for (i = 0; i < 4; i++) + { + assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); + } + + phal_thread_sleep(1000); + + for (i = 0; i < 4; i++) + { + void * retValue; + assert(pthread_join(id[i],&retValue) == 0); + assert((int)retValue == i); + } + + /* Success. */ + return 0; +} diff --git a/pthread/tests/exit4.c b/pthread/tests/exit4.c new file mode 100644 index 00000000..82e96674 --- /dev/null +++ b/pthread/tests/exit4.c @@ -0,0 +1,197 @@ +/* + * File: exit4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test calling pthread_exit from a Win32 thread + * without having created an implicit POSIX handle for it. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + + + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 5 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + + +static int osThread(void * arg) +{ + int result = 1; + bag_t * bag = *((bag_t **) arg); + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* + * Doesn't return and doesn't create an implicit POSIX handle. + */ + pthread_exit((void *) result); + + return 0; +} + + + +int pthread_test_exit4() +{ + int failed = 0; + int i; + phal_tid h[NUMTHREADS + 1]; + + for (i = 1; i <= NUMTHREADS; i++) + { + void *ptr; + + /* + char threadName[32]; + snprintf(threadName, sizeof(threadName), "test_th%d", i); + */ + + threadbag[i].started = 0; + threadbag[i].threadnum = i; + + ptr = &(threadbag[i]); + + phal_thread_create(&h[i], osThread, ptr); + + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * Can't get a result code. + */ + result = 1; + + fail = (result != 1); + + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} + diff --git a/pthread/tests/exit5.c b/pthread/tests/exit5.c new file mode 100644 index 00000000..d5dc079e --- /dev/null +++ b/pthread/tests/exit5.c @@ -0,0 +1,203 @@ +/* + * File: exit5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Test calling pthread_exit from a Win32 thread + * having created an implicit POSIX handle for it. + * + * Test Method (Validation or Falsification): + * - Validate return value and that POSIX handle is created and destroyed. + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum +{ + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ + { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; + pthread_t self; + }; + +static bag_t threadbag[NUMTHREADS + 1]; + +static int osThread(void * arg) +{ + int result = 1; + bag_t * bag = *((bag_t **) arg); + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + assert((bag->self = pthread_self()) != NULL); + assert(pthread_kill(bag->self, 0) == 0); + + /* + * Doesn't return. + */ + pthread_exit((void *) result); + + return 0; +} + + + +int pthread_test_exit5() +{ + int failed = 0; + int i; + phal_tid h[NUMTHREADS + 1]; + + for (i = 1; i <= NUMTHREADS; i++) + { + void *ptr; + + threadbag[i].started = 0; + threadbag[i].threadnum = i; + + ptr = &(threadbag[i]); + + phal_thread_create(&h[i], osThread, &ptr); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + phal_thread_sleep(500); + + + /* + * Give threads time to run. + */ + phal_thread_sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * Can't get a result code. + */ + result = 1; + + assert(threadbag[i].self != NULL && pthread_kill(threadbag[i].self, 0) == ESRCH); + + fail = (result != 1); + + if (fail) + { + fprintf(stderr, "Thread %d: started %d: count %d\n", + i, + threadbag[i].started, + threadbag[i].count); + } + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} + diff --git a/pthread/tests/inherit1.c b/pthread/tests/inherit1.c new file mode 100644 index 00000000..d7c10008 --- /dev/null +++ b/pthread/tests/inherit1.c @@ -0,0 +1,145 @@ +/* + * File: inherit1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test thread priority inheritance. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +enum +{ + PTW32TEST_THREAD_INIT_PRIO = 0, + PTW32TEST_MAXPRIORITIES = 512 +}; + +static void * func(void * arg) +{ + int policy; + struct sched_param param; + + assert(pthread_getschedparam(pthread_self(), &policy, ¶m) == 0); + + return (void *) param.sched_priority; +} + +int pthread_test_inherit1() +{ + pthread_t t; + pthread_t mainThread = pthread_self(); + pthread_attr_t attr; + int result = 0; + struct sched_param param; + struct sched_param mainParam; + int prio; + int policy; + int inheritsched = -1; + + assert(pthread_attr_init(&attr) == 0); + assert(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) == 0); + assert(pthread_attr_getinheritsched(&attr, &inheritsched) == 0); + assert(inheritsched == PTHREAD_INHERIT_SCHED); + + for (prio = pte_osThreadGetMinPriority(); + prio <= pte_osThreadGetMaxPriority(); + prio++) + { + mainParam.sched_priority = prio; + + /* Change the main thread priority */ + assert(pthread_setschedparam(mainThread, SCHED_OTHER, &mainParam) == 0); + assert(pthread_getschedparam(mainThread, &policy, &mainParam) == 0); + assert(policy == SCHED_OTHER); + /* Priority returned below should be the level set by pthread_setschedparam(). */ + assert(mainParam.sched_priority == prio); + + pte_osThreadSetPriority(pte_osThreadGetHandle(), prio); + + assert(pte_osThreadGetPriority(pte_osThreadGetHandle()) == prio); + + for (param.sched_priority = prio; + param.sched_priority <= pte_osThreadGetMaxPriority(); + param.sched_priority++) + { + /* The new thread create should ignore this new priority */ + assert(pthread_attr_setschedparam(&attr, ¶m) == 0); + assert(pthread_create(&t, &attr, func, NULL) == 0); + pthread_join(t, (void **)&result); + assert((int) result == mainParam.sched_priority); + } + } + + return 0; +} diff --git a/pthread/tests/join0.c b/pthread/tests/join0.c new file mode 100644 index 00000000..06c8ff87 --- /dev/null +++ b/pthread/tests/join0.c @@ -0,0 +1,75 @@ +/* + * Test for pthread_join(). + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: pthread_create(), pthread_exit(). + */ + +#include "test.h" + +static void * +func(void * arg) +{ + phal_thread_sleep(2000); + + pthread_exit(arg); + + /* Never reached. */ + exit(1); + + return 0; +} + + +int pthread_test_join0() +{ + pthread_t id; + int result; + + /* Create a single thread and wait for it to exit. */ + assert(pthread_create(&id, NULL, func, (void *) 123) == 0); + + assert(pthread_join(id, (void **) &result) == 0); + + assert(result == 123); + + /* Success. */ + return 0; +} diff --git a/pthread/tests/join1.c b/pthread/tests/join1.c new file mode 100644 index 00000000..ad7bc7bc --- /dev/null +++ b/pthread/tests/join1.c @@ -0,0 +1,83 @@ +/* + * Test for pthread_join(). + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: pthread_create(), pthread_join(), pthread_exit(). + */ + +#include "test.h" + +static void * +func(void * arg) +{ + int i = (int) arg; + + phal_thread_sleep(i * 100); + + pthread_exit(arg); + + /* Never reached. */ + return 0; +} + +int pthread_test_join1() +{ + pthread_t id[4]; + int i; + int result; + + /* Create a few threads and then exit. */ + for (i = 0; i < 4; i++) + { + assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); + } + + /* Some threads will finish before they are joined, some after. */ + phal_thread_sleep(20 * 100 + 50); + + for (i = 0; i < 4; i++) + { + assert(pthread_join(id[i], (void **) &result) == 0); + assert(result == i); + } + + /* Success. */ + return 0; +} diff --git a/pthread/tests/join2.c b/pthread/tests/join2.c new file mode 100644 index 00000000..a6f91470 --- /dev/null +++ b/pthread/tests/join2.c @@ -0,0 +1,74 @@ +/* + * Test for pthread_join() returning return value from threads. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: pthread_create(). + */ + +#include "test.h" + +static void * +func(void * arg) +{ + phal_thread_sleep(2000); + return arg; +} + +int pthread_test_join2() +{ + pthread_t id[4]; + int i; + int result; + + /* Create a few threads and then exit. */ + for (i = 0; i < 4; i++) + { + assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); + } + + for (i = 0; i < 4; i++) + { + assert(pthread_join(id[i], (void **) &result) == 0); + assert(result == i); + } + + /* Success. */ + return 0; +} diff --git a/pthread/tests/join3.c b/pthread/tests/join3.c new file mode 100644 index 00000000..3dd04b40 --- /dev/null +++ b/pthread/tests/join3.c @@ -0,0 +1,82 @@ +/* + * Test for pthread_join() returning return value from threads. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Depends on API functions: pthread_create(). + */ + +#include "test.h" + +static void * +func(void * arg) +{ + // TODO: sched_yield + //sched_yield(); + phal_thread_sleep(0); + return arg; +} + +int pthread_test_join3() +{ + pthread_t id[4]; + int i; + int result; + + /* Create a few threads and then exit. */ + for (i = 0; i < 4; i++) + { + assert(pthread_create(&id[i], NULL, func, (void *) i) == 0); + } + + /* + * Let threads exit before we join them. + * We should still retrieve the exit code for the threads. + */ + phal_thread_sleep(1000); + + for (i = 0; i < 4; i++) + { + assert(pthread_join(id[i], (void **) &result) == 0); + assert(result == i); + } + + /* Success. */ + return 0; +} diff --git a/pthread/tests/join4.c b/pthread/tests/join4.c new file mode 100644 index 00000000..613e5e5a --- /dev/null +++ b/pthread/tests/join4.c @@ -0,0 +1,83 @@ +/* + * Test for pthread_join() returning return value from threads. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Verifies that pthread_join can be cancelled. + */ + +#include "test.h" + +static pthread_t handle1; +static pthread_t handle2; + +static int thread2_status; + +static void * +thr1(void * arg) +{ + phal_thread_sleep(5000); + + return NULL; +} + +static void * +thr2(void * arg) +{ + int result; + + assert(pthread_join(handle1,NULL) == 0); + + thread2_status = 1; + + return NULL; +} + +int pthread_test_join4() +{ + thread2_status = 0; + + assert(pthread_create(&handle1, NULL, thr1, NULL) == 0); + assert(pthread_create(&handle2, NULL, thr2, NULL) == 0); + + /* Give some time for thread #1 to start sleeping and thread #2 to wait on thread #1 */ + phal_thread_sleep(500); + + /* Cancel thread #2 (who is waiting on thread #1) */ + assert(pthread_cancel(handle2) == 0); + + /* Wait a short amount of time for cancellation to take effect */ + phal_thread_sleep(500); + + /* Make sure that pthread_join exited after cancellation */ + assert(thread2_status == 1); + + assert(pthread_join(handle1, NULL) == 0); + assert(pthread_join(handle2, NULL) == 0); + + /* Success. */ + return 0; +} diff --git a/pthread/tests/kill1.c b/pthread/tests/kill1.c new file mode 100644 index 00000000..7abf564e --- /dev/null +++ b/pthread/tests/kill1.c @@ -0,0 +1,88 @@ +/* + * File: kill1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - pthread_kill() does not support non zero signals.. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + + +int pthread_test_kill1() +{ + assert(pthread_kill(pthread_self(), 1) == EINVAL); + + return 0; +} diff --git a/pthread/tests/main.c b/pthread/tests/main.c new file mode 100644 index 00000000..c0cab980 --- /dev/null +++ b/pthread/tests/main.c @@ -0,0 +1,5 @@ +extern void pte_test_main(); + +int main() { + pte_test_main(); +} diff --git a/pthread/tests/mutex1.c b/pthread/tests/mutex1.c new file mode 100644 index 00000000..1cf4e944 --- /dev/null +++ b/pthread/tests/mutex1.c @@ -0,0 +1,79 @@ +/* + * mutex1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create a simple mutex object, lock it, and then unlock it again. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + * pthread_mutex_destroy() + */ + +#include +#include + +#include "test.h" + + + +static pthread_mutex_t mutex = NULL; + +int +pthread_test_mutex1() +{ + assert(mutex == NULL); + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + assert(mutex != NULL); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex1e.c b/pthread/tests/mutex1e.c new file mode 100644 index 00000000..af46561c --- /dev/null +++ b/pthread/tests/mutex1e.c @@ -0,0 +1,83 @@ +/* + * mutex1e.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * As for mutex1.c but with type set to PTHREAD_MUTEX_ERRORCHECK. + * + * Create a simple mutex object, lock it, unlock it, then destroy it. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + * pthread_mutexattr_settype() + * pthread_mutex_init() + * pthread_mutex_destroy() + */ + +#include +#include + +#include "test.h" + +static pthread_mutex_t mutex = NULL; +static pthread_mutexattr_t mxAttr; + +int +pthread_test_mutex1e() +{ + assert(pthread_mutexattr_init(&mxAttr) == 0); + + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); + + assert(mutex == NULL); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(mutex != NULL); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex1n.c b/pthread/tests/mutex1n.c new file mode 100644 index 00000000..b0eb5de9 --- /dev/null +++ b/pthread/tests/mutex1n.c @@ -0,0 +1,82 @@ +/* + * mutex1n.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * As for mutex1.c but with type set to PTHREAD_MUTEX_NORMAL. + * + * Create a simple mutex object, lock it, unlock it, then destroy it. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + * pthread_mutexattr_settype() + * pthread_mutex_init() + * pthread_mutex_destroy() + */ + +#include +#include +#include "test.h" + +static pthread_mutex_t mutex = NULL; +static pthread_mutexattr_t mxAttr; + +int +pthread_test_mutex1n() +{ + assert(pthread_mutexattr_init(&mxAttr) == 0); + + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); + + assert(mutex == NULL); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(mutex != NULL); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex1r.c b/pthread/tests/mutex1r.c new file mode 100644 index 00000000..fb1ae426 --- /dev/null +++ b/pthread/tests/mutex1r.c @@ -0,0 +1,83 @@ +/* + * mutex1r.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * As for mutex1.c but with type set to PTHREAD_MUTEX_RECURSIVE. + * + * Create a simple mutex object, lock it, unlock it, then destroy it. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + * pthread_mutexattr_settype() + * pthread_mutex_init() + * pthread_mutex_destroy() + */ + +#include +#include + +#include "test.h" + +static pthread_mutex_t mutex = NULL; +static pthread_mutexattr_t mxAttr; + +int +pthread_test_mutex1r() +{ + assert(pthread_mutexattr_init(&mxAttr) == 0); + + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); + + assert(mutex == NULL); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(mutex != NULL); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex2.c b/pthread/tests/mutex2.c new file mode 100644 index 00000000..1ff85ae7 --- /dev/null +++ b/pthread/tests/mutex2.c @@ -0,0 +1,77 @@ +/* + * mutex2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static mutex object, lock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +int +pthread_test_mutex2() +{ + mutex = PTHREAD_MUTEX_INITIALIZER; + + assert(mutex == PTHREAD_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(mutex != PTHREAD_MUTEX_INITIALIZER); + + assert(mutex != NULL); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex2e.c b/pthread/tests/mutex2e.c new file mode 100644 index 00000000..0ac80873 --- /dev/null +++ b/pthread/tests/mutex2e.c @@ -0,0 +1,80 @@ +/* + * mutex2e.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static mutex object, lock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +int +pthread_test_mutex2e() +{ + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + assert(pthread_mutexattr_init(&attr) == 0); + assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex, &attr) == 0); + + //assert(mutex == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&mutex) == 0); + + //assert(mutex != PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); + + assert(mutex != NULL); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex2r.c b/pthread/tests/mutex2r.c new file mode 100644 index 00000000..bb53765a --- /dev/null +++ b/pthread/tests/mutex2r.c @@ -0,0 +1,80 @@ +/* + * mutex2r.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static mutex object, lock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +int +pthread_test_mutex2r() +{ + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + assert(pthread_mutexattr_init(&attr) == 0); + assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex, &attr) == 0); + + //assert(mutex == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); + + assert(pthread_mutex_lock(&mutex) == 0); + + //assert(mutex != PTHREAD_ERRORCHECK_MUTEX_INITIALIZER); + + assert(mutex != NULL); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + assert(mutex == NULL); + + return 0; +} diff --git a/pthread/tests/mutex3.c b/pthread/tests/mutex3.c new file mode 100644 index 00000000..57fc5a8d --- /dev/null +++ b/pthread/tests/mutex3.c @@ -0,0 +1,88 @@ +/* + * mutex3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static mutex object, lock it, trylock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_mutex_trylock(&mutex1) == EBUSY); + + washere = 1; + + return 0; +} + +int +pthread_test_mutex3() +{ + pthread_t t; + + mutex1 = PTHREAD_MUTEX_INITIALIZER; + + assert(pthread_mutex_lock(&mutex1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + + assert(pthread_mutex_unlock(&mutex1) == 0); + + assert(washere == 1); + + assert(pthread_mutex_destroy(&mutex1) == 0); + + return 0; +} diff --git a/pthread/tests/mutex3e.c b/pthread/tests/mutex3e.c new file mode 100644 index 00000000..24c7c9b3 --- /dev/null +++ b/pthread/tests/mutex3e.c @@ -0,0 +1,92 @@ +/* + * mutex3e.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static mutex object, lock it, trylock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static pthread_mutex_t mutex1; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_mutex_trylock(&mutex1) == EBUSY); + + washere = 1; + + return 0; +} + +int +pthread_test_mutex3e() +{ + pthread_t t; + pthread_mutexattr_t attr; + + assert(pthread_mutexattr_init(&attr) == 0); + assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex1, &attr) == 0); + + assert(pthread_mutex_lock(&mutex1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + assert(pthread_join(t, NULL) == 0); + + assert(pthread_mutex_unlock(&mutex1) == 0); + + assert(pthread_mutex_destroy(&mutex1) == 0); + + assert(washere == 1); + + return 0; +} diff --git a/pthread/tests/mutex3r.c b/pthread/tests/mutex3r.c new file mode 100644 index 00000000..f9996888 --- /dev/null +++ b/pthread/tests/mutex3r.c @@ -0,0 +1,92 @@ +/* + * mutex3r.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static mutex object, lock it, trylock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static pthread_mutex_t mutex1; + +static int washere = 0; + +void * func(void * arg) +{ + assert(pthread_mutex_trylock(&mutex1) == EBUSY); + + washere = 1; + + return 0; +} + +int +pthread_test_mutex3r() +{ + pthread_t t; + + pthread_mutexattr_t attr; + + assert(pthread_mutexattr_init(&attr) == 0); + assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex1, &attr) == 0); + + assert(pthread_mutex_lock(&mutex1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + + assert(pthread_mutex_unlock(&mutex1) == 0); + + assert(washere == 1); + + assert(pthread_mutex_destroy(&mutex1) == 0); + + return 0; +} diff --git a/pthread/tests/mutex4.c b/pthread/tests/mutex4.c new file mode 100644 index 00000000..29fb9fad --- /dev/null +++ b/pthread/tests/mutex4.c @@ -0,0 +1,126 @@ +/* + * mutex4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Thread A locks mutex - thread B tries to unlock. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int wasHere = 0; + +static pthread_mutex_t mutex1; + +void * unlocker(void * arg) +{ + int expectedResult = (int) arg; + + wasHere++; + assert(pthread_mutex_unlock(&mutex1) == expectedResult); + wasHere++; + return NULL; +} + +int +pthread_test_mutex4() +{ + pthread_t t; + pthread_mutexattr_t ma; + + assert(pthread_mutexattr_init(&ma) == 0); + + wasHere = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_DEFAULT) == 0); + assert(pthread_mutex_init(&mutex1, &ma) == 0); + assert(pthread_mutex_lock(&mutex1) == 0); + /* + * NORMAL (fast) mutexes don't check ownership. + * STRICT mutexes do. The default is STRICT ! + */ + assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_mutex_unlock(&mutex1) == EPERM); + assert(wasHere == 2); + assert(pthread_mutex_destroy(&mutex1) == 0); + + wasHere = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutex_init(&mutex1, &ma) == 0); + assert(pthread_mutex_lock(&mutex1) == 0); + /* + * NORMAL (fast) mutexes don't check ownership. + */ + assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_mutex_unlock(&mutex1) == EPERM); + assert(wasHere == 2); + assert(pthread_mutex_destroy(&mutex1) == 0); + + + wasHere = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex1, &ma) == 0); + assert(pthread_mutex_lock(&mutex1) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_mutex_unlock(&mutex1) == 0); + assert(wasHere == 2); + assert(pthread_mutex_destroy(&mutex1) == 0); + + wasHere = 0; + assert(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex1, &ma) == 0); + assert(pthread_mutex_lock(&mutex1) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *) EPERM) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_mutex_unlock(&mutex1) == 0); + assert(wasHere == 2); + assert(pthread_mutex_destroy(&mutex1) == 0); + + return 0; +} diff --git a/pthread/tests/mutex5.c b/pthread/tests/mutex5.c new file mode 100644 index 00000000..dcb8ed32 --- /dev/null +++ b/pthread/tests/mutex5.c @@ -0,0 +1,78 @@ +/* + * mutex5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Confirm the equality/inequality of the various mutex types, + * and the default not-set value. + */ + +#include +#include + +#include "test.h" + +static pthread_mutexattr_t mxAttr; + +/* Prevent optimiser from removing dead or obvious asserts. */ +int _optimiseFoil; +#define FOIL(x) (_optimiseFoil = x) + +int +pthread_test_mutex5() +{ + int mxType = -1; + + assert(FOIL(PTHREAD_MUTEX_DEFAULT) == PTHREAD_MUTEX_STRICT_NP); + assert(FOIL(PTHREAD_MUTEX_DEFAULT) != PTHREAD_MUTEX_NORMAL); + assert(FOIL(PTHREAD_MUTEX_DEFAULT) != PTHREAD_MUTEX_ERRORCHECK); + assert(FOIL(PTHREAD_MUTEX_DEFAULT) != PTHREAD_MUTEX_RECURSIVE); + assert(FOIL(PTHREAD_MUTEX_RECURSIVE) != PTHREAD_MUTEX_ERRORCHECK); + + // No need for non-portable. + /*assert(FOIL(PTHREAD_MUTEX_NORMAL) == PTHREAD_MUTEX_FAST_NP); + assert(FOIL(PTHREAD_MUTEX_RECURSIVE) == PTHREAD_MUTEX_RECURSIVE_NP); + assert(FOIL(PTHREAD_MUTEX_ERRORCHECK) == PTHREAD_MUTEX_ERRORCHECK_NP);*/ + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_STRICT_NP); + + return 0; +} diff --git a/pthread/tests/mutex6.c b/pthread/tests/mutex6.c new file mode 100644 index 00000000..1df6a024 --- /dev/null +++ b/pthread/tests/mutex6.c @@ -0,0 +1,109 @@ +/* + * mutex6.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test the default (type not set) mutex type. + * Should be the same as PTHREAD_MUTEX_NORMAL. + * Thread locks mutex twice (recursive lock). + * Locking thread should deadlock on second attempt. + * + * PHAL: The default is actually PTHREAD_MUTEX_STRICT_NP, which aborts in case + * of undef behavior. We'll force set it to PTHREAD_MUTEX_NORMAL. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + + /* Should wait here (deadlocked) */ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + + assert(pthread_mutex_unlock(&mutex) == 0); + + return 0; +} + +int +pthread_test_mutex6() +{ + pthread_t t; + + lockCount = 0; + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 1); + + /* + * Should succeed even though we don't own the lock + * because FAST mutexes don't check ownership. + */ + assert(pthread_mutex_unlock(&mutex) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 2); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/mutex6e.c b/pthread/tests/mutex6e.c new file mode 100644 index 00000000..5a74a5ed --- /dev/null +++ b/pthread/tests/mutex6e.c @@ -0,0 +1,109 @@ +/* + * mutex6e.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_ERRORCHECK mutex type. + * Thread locks mutex twice (recursive lock). + * This should fail with an EDEADLK error. + * The second unlock attempt should fail with an EPERM error. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex) == EDEADLK); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == EPERM); + + return (void *) 555; +} + +int +pthread_test_mutex6e() +{ + pthread_t t; + int result = 0; + int mxType = -1; + + lockCount = 0; + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_ERRORCHECK); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == 555); + + assert(lockCount == 2); + + assert(pthread_mutex_destroy(&mutex) == 0); + assert(pthread_mutexattr_destroy(&mxAttr) == 0); + + return 0; +} + diff --git a/pthread/tests/mutex6es.c b/pthread/tests/mutex6es.c new file mode 100644 index 00000000..c75e17e5 --- /dev/null +++ b/pthread/tests/mutex6es.c @@ -0,0 +1,105 @@ +/* + * mutex6es.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_ERRORCHECK static mutex type. + * Thread locks mutex twice (recursive lock). + * This should fail with an EDEADLK error. + * The second unlock attempt should fail with an EPERM error. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex) == EDEADLK); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == EPERM); + + return (void *) 555; +} + +int +pthread_test_mutex6es() +{ + pthread_t t; + pthread_mutexattr_t attr; + int result = 0; + + lockCount = 0; + + assert(pthread_mutexattr_init(&attr) == 0); + assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutex_init(&mutex, &attr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == 555); + + assert(lockCount == 2); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} + diff --git a/pthread/tests/mutex6n.c b/pthread/tests/mutex6n.c new file mode 100644 index 00000000..36fd07cb --- /dev/null +++ b/pthread/tests/mutex6n.c @@ -0,0 +1,121 @@ +/* + * mutex6n.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_NORMAL mutex type. + * Thread locks mutex twice (recursive lock). + * The thread should deadlock. + * + * Depends on API functions: + * pthread_create() + * pthread_mutexattr_init() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + + /* Should wait here (deadlocked) */ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + +// JNS: Why is this done? The mutex should already +// be unlocked by the main thread, so this call +// will always return EPERM... +// assert(pthread_mutex_unlock(&mutex) == 0); + + return (void *) 555; +} + +int +pthread_test_mutex6n() +{ + pthread_t t; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_NORMAL); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 1); + + /* + * Should succeed even though we don't own the lock + * because FAST mutexes don't check ownership. + */ + assert(pthread_mutex_unlock(&mutex) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 2); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} + diff --git a/pthread/tests/mutex6r.c b/pthread/tests/mutex6r.c new file mode 100644 index 00000000..9733471e --- /dev/null +++ b/pthread/tests/mutex6r.c @@ -0,0 +1,108 @@ +/* + * mutex6r.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_RECURSIVE mutex type. + * Thread locks mutex twice (recursive lock). + * Both locks and unlocks should succeed. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + + return (void *) 555; +} + +int +pthread_test_mutex6r() +{ + pthread_t t; + int result = 0; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_RECURSIVE); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == 555); + + assert(lockCount == 2); + + assert(pthread_mutex_destroy(&mutex) == 0); + assert(pthread_mutexattr_destroy(&mxAttr) == 0); + + return 0; +} diff --git a/pthread/tests/mutex6rs.c b/pthread/tests/mutex6rs.c new file mode 100644 index 00000000..8efd109a --- /dev/null +++ b/pthread/tests/mutex6rs.c @@ -0,0 +1,104 @@ +/* + * mutex6rs.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_RECURSIVE static mutex type. + * Thread locks mutex twice (recursive lock). + * Both locks and unlocks should succeed. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; + +void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + + return (void *) 555; +} + +int +pthread_test_mutex6rs() +{ + pthread_t t; + int result = 0; + + lockCount = 0; + + pthread_mutexattr_t attr; + + assert(pthread_mutexattr_init(&attr) == 0); + assert(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutex_init(&mutex, &attr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == 555); + + assert(lockCount == 2); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/mutex6s.c b/pthread/tests/mutex6s.c new file mode 100644 index 00000000..ffd545fe --- /dev/null +++ b/pthread/tests/mutex6s.c @@ -0,0 +1,108 @@ +/* + * mutex6s.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test the default (type not set) static mutex type. + * Should be the same as PTHREAD_MUTEX_NORMAL. + * Thread locks mutex twice (recursive lock). + * Locking thread should deadlock on second attempt. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + + /* Should wait here (deadlocked) */ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + + + return 0; +} + +int +pthread_test_mutex6s() +{ + pthread_t t; + + lockCount = 0; + mutex = PTHREAD_MUTEX_INITIALIZER; + + assert(mutex == PTHREAD_MUTEX_INITIALIZER); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 1); + + /* + * Should succeed even though we don't own the lock + * because FAST mutexes don't check ownership. + */ + assert(pthread_mutex_unlock(&mutex) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 2); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/mutex7.c b/pthread/tests/mutex7.c new file mode 100644 index 00000000..fddc79c7 --- /dev/null +++ b/pthread/tests/mutex7.c @@ -0,0 +1,95 @@ +/* + * mutex7.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test the default (type not set) mutex type. + * Should be the same as PTHREAD_MUTEX_NORMAL. + * Thread locks then trylocks mutex (attempted recursive lock). + * The thread should lock first time and EBUSY second time. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_trylock(&mutex) == EBUSY); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == EPERM); + + return 0; +} + +int +pthread_test_mutex7() +{ + pthread_t t; + + lockCount = 0; + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(1000); + + assert(lockCount == 2); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + /* Never reached */ + return 0; +} diff --git a/pthread/tests/mutex7e.c b/pthread/tests/mutex7e.c new file mode 100644 index 00000000..572841e7 --- /dev/null +++ b/pthread/tests/mutex7e.c @@ -0,0 +1,111 @@ +/* + * mutex7e.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_ERRORCHECK mutex type. + * Thread locks and then trylocks mutex (attempted recursive lock). + * Trylock should fail with an EBUSY error. + * The second unlock attempt should fail with an EPERM error. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_trylock(&mutex) == EBUSY); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == EPERM); + + return (void *) 555; +} + +int +pthread_test_mutex7e() +{ + pthread_t t; + int result = 0; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_ERRORCHECK); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == 555); + + assert(lockCount == 2); + + assert(pthread_mutex_destroy(&mutex) == 0); + assert(pthread_mutexattr_destroy(&mxAttr) == 0); + + /* Never reached */ + return 0; +} + diff --git a/pthread/tests/mutex7n.c b/pthread/tests/mutex7n.c new file mode 100644 index 00000000..958083af --- /dev/null +++ b/pthread/tests/mutex7n.c @@ -0,0 +1,110 @@ +/* + * mutex7n.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_NORMAL mutex type. + * Thread locks then trylocks mutex (attempted recursive lock). + * The thread should lock first time and EBUSY second time. + * + * PHAL fix: unlocking an unlocked mutex returns 0. + * + * Depends on API functions: + * pthread_create() + * pthread_mutexattr_init() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_trylock(&mutex) == EBUSY); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + // Unlocking an unlocked mutex returns 0; + assert(pthread_mutex_unlock(&mutex) == 0); + + return (void *) 555; +} + +int +pthread_test_mutex7n() +{ + pthread_t t; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_NORMAL); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + // Yield multiple times. Yes this sucks. Mephisto doesn't understand timeouts. + phal_thread_sleep(1000); + phal_thread_sleep(1000); + + assert(lockCount == 2); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + /* Never reached */ + return 0; +} + diff --git a/pthread/tests/mutex7r.c b/pthread/tests/mutex7r.c new file mode 100644 index 00000000..ab2a070b --- /dev/null +++ b/pthread/tests/mutex7r.c @@ -0,0 +1,108 @@ +/* + * mutex7r.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Tests PTHREAD_MUTEX_RECURSIVE mutex type. + * Thread locks mutex then trylocks mutex (recursive lock twice). + * Both locks and unlocks should succeed. + * + * Depends on API functions: + * pthread_create() + * pthread_join() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + assert(pthread_mutex_lock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_trylock(&mutex) == 0); + lockCount++; + assert(pthread_mutex_unlock(&mutex) == 0); + assert(pthread_mutex_unlock(&mutex) == 0); + + return (void *) 555; +} + +int +pthread_test_mutex7r() +{ + pthread_t t; + int result = 0; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_RECURSIVE); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result == 555); + + assert(lockCount == 2); + + assert(pthread_mutex_destroy(&mutex) == 0); + assert(pthread_mutexattr_destroy(&mxAttr) == 0); + + return 0; +} diff --git a/pthread/tests/mutex8.c b/pthread/tests/mutex8.c new file mode 100644 index 00000000..d566db7b --- /dev/null +++ b/pthread/tests/mutex8.c @@ -0,0 +1,100 @@ +/* + * mutex8.c + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 Ben Elliston and Ross Johnson + * Copyright (C) 1999,2000,2001 Ross Johnson + * + * Contact Email: rpj@ise.canberra.edu.au + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Test the default (type not set) mutex type exercising timedlock. + * Thread locks mutex, another thread timedlocks the mutex. + * Timed thread should timeout. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_timedlock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + + +static int lockCount = 0; + +static pthread_mutex_t mutex; + +static void * locker(void * arg) +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeb currSysTime; + const unsigned long NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + currSysTime.tv_sec += 1; // wait for one seconds + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); + + lockCount++; + + return 0; +} + +int +pthread_test_mutex8() +{ + pthread_t t; + + lockCount = 0; + + assert(pthread_mutex_init(&mutex, NULL) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(2000); + + assert(lockCount == 1); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} diff --git a/pthread/tests/mutex8e.c b/pthread/tests/mutex8e.c new file mode 100644 index 00000000..edb7cd33 --- /dev/null +++ b/pthread/tests/mutex8e.c @@ -0,0 +1,114 @@ +/* + * mutex8e.c + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 Ben Elliston and Ross Johnson + * Copyright (C) 1999,2000,2001 Ross Johnson + * + * Contact Email: rpj@ise.canberra.edu.au + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Tests PTHREAD_MUTEX_ERRORCHECK mutex type exercising timedlock. + * Thread locks mutex, another thread timedlocks the mutex. + * Timed thread should timeout. + * + * Depends on API functions: + * pthread_create() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_timedlock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned long NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); + + lockCount++; + + return 0; +} + +int +pthread_test_mutex8e() +{ + pthread_t t; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_ERRORCHECK); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(2000); + + assert(lockCount == 1); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} + diff --git a/pthread/tests/mutex8n.c b/pthread/tests/mutex8n.c new file mode 100644 index 00000000..a76c73a6 --- /dev/null +++ b/pthread/tests/mutex8n.c @@ -0,0 +1,114 @@ +/* + * mutex8n.c + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 Ben Elliston and Ross Johnson + * Copyright (C) 1999,2000,2001 Ross Johnson + * + * Contact Email: rpj@ise.canberra.edu.au + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Tests PTHREAD_MUTEX_NORMAL mutex type exercising timedlock. + * Thread locks mutex, another thread timedlocks the mutex. + * Timed thread should timeout. + * + * Depends on API functions: + * pthread_create() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_timedlock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); + + lockCount++; + + return 0; +} + +int +pthread_test_mutex8n() +{ + pthread_t t; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_NORMAL); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(2000); + + assert(lockCount == 1); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} + diff --git a/pthread/tests/mutex8r.c b/pthread/tests/mutex8r.c new file mode 100644 index 00000000..7eb98c20 --- /dev/null +++ b/pthread/tests/mutex8r.c @@ -0,0 +1,114 @@ +/* + * mutex8r.c + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 Ben Elliston and Ross Johnson + * Copyright (C) 1999,2000,2001 Ross Johnson + * + * Contact Email: rpj@ise.canberra.edu.au + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Tests PTHREAD_MUTEX_RECURSIVE mutex type exercising timedlock. + * Thread locks mutex, another thread timedlocks the mutex. + * Timed thread should timeout. + * + * Depends on API functions: + * pthread_create() + * pthread_mutexattr_init() + * pthread_mutexattr_destroy() + * pthread_mutexattr_settype() + * pthread_mutexattr_gettype() + * pthread_mutex_init() + * pthread_mutex_destroy() + * pthread_mutex_lock() + * pthread_mutex_timedlock() + * pthread_mutex_unlock() + */ + +#include +#include + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +static void * locker(void * arg) +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const unsigned int NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(pthread_mutex_timedlock(&mutex, &abstime) == ETIMEDOUT); + + lockCount++; + + return 0; +} + +int +pthread_test_mutex8r() +{ + pthread_t t; + int mxType = -1; + + lockCount = 0; + + assert(pthread_mutexattr_init(&mxAttr) == 0); + assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); + assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); + assert(mxType == PTHREAD_MUTEX_RECURSIVE); + + assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + + assert(pthread_mutex_lock(&mutex) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + + phal_thread_sleep(2000); + + assert(lockCount == 1); + + assert(pthread_mutex_unlock(&mutex) == 0); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_mutex_destroy(&mutex) == 0); + + return 0; +} + diff --git a/pthread/tests/once1.c b/pthread/tests/once1.c new file mode 100644 index 00000000..18b6c031 --- /dev/null +++ b/pthread/tests/once1.c @@ -0,0 +1,90 @@ +/* + * once1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create a static pthread_once and test that it calls myfunc once. + * + * Depends on API functions: + * pthread_once() + * pthread_create() + */ + +#include "test.h" + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static int washere = 0; + +static void +myfunc(void) +{ + washere++; +} + +static void * +mythread(void * arg) +{ + assert(pthread_once(&once, myfunc) == 0); + + return 0; +} + +int pthread_test_once1() +{ + pthread_t t1, t2; + pthread_once_t onceinit = PTHREAD_ONCE_INIT; + + washere = 0; + + once = onceinit; + + assert(pthread_create(&t1, NULL, mythread, NULL) == 0); + + assert(pthread_create(&t2, NULL, mythread, NULL) == 0); + + phal_thread_sleep(2000); + + assert(washere == 1); + + assert(pthread_join(t1,NULL) == 0); + assert(pthread_join(t2,NULL) == 0); + + return 0; +} diff --git a/pthread/tests/once2.c b/pthread/tests/once2.c new file mode 100644 index 00000000..34773df3 --- /dev/null +++ b/pthread/tests/once2.c @@ -0,0 +1,134 @@ +/* + * once2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create several static pthread_once objects and channel several threads + * through each. + * + * Depends on API functions: + * pthread_once() + * pthread_create() + */ + +#include "test.h" + +#define NUM_THREADS OS_MAX_SIMUL_THREADS / 5 /* Targeting each once control */ +#define NUM_ONCE 5 + + +static pthread_once_t o = PTHREAD_ONCE_INIT; +static pthread_once_t once[NUM_ONCE]; + +typedef struct + { + int i; + phal_mutex cs; + } sharedInt_t; + +static sharedInt_t numOnce = {0, 0}; +static sharedInt_t numThreads = {0, 0}; + +static void +myfunc(void) +{ + + phal_mutex_lock(numOnce.cs); + + numOnce.i++; + + phal_mutex_unlock(numOnce.cs); + + /* Simulate slow once routine so that following threads pile up behind it */ + phal_thread_sleep(100); +} + +static void * +mythread(void * arg) +{ + + assert(pthread_once(&once[(int) arg], myfunc) == 0); + + phal_mutex_lock(numThreads.cs); + numThreads.i++; + phal_mutex_unlock(numThreads.cs); + + return 0; +} + +int pthread_test_once2() +{ + pthread_t t[NUM_THREADS][NUM_ONCE]; + int i, j; + int result; + + numOnce.i = 0; + numThreads.i = 0; + + phal_mutex_create(&numThreads.cs); + phal_mutex_create(&numOnce.cs); + + for (j = 0; j < NUM_ONCE; j++) + { + once[j] = o; + + for (i = 0; i < NUM_THREADS; i++) + assert(pthread_create(&t[i][j], NULL, mythread, (void *) j) == 0); + } + + for (j = 0; j < NUM_ONCE; j++) + for (i = 0; i < NUM_THREADS; i++) + if ((result = pthread_join(t[i][j], NULL)) != 0) + { + assert(0); //Join failed for [thread,once] + } + + /* Stop some compilers from generating warning */ + result = result; + + phal_thread_sleep(1000); + + assert(numOnce.i == NUM_ONCE); + assert(numThreads.i == NUM_THREADS * NUM_ONCE); + + phal_mutex_destroy(numOnce.cs); + phal_mutex_destroy(numThreads.cs); + + return 0; +} diff --git a/pthread/tests/once3.c b/pthread/tests/once3.c new file mode 100644 index 00000000..1b3f4566 --- /dev/null +++ b/pthread/tests/once3.c @@ -0,0 +1,151 @@ +/* + * once3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create several pthread_once objects and channel several threads + * through each. Make the init_routine cancelable and cancel them with + * waiters waiting. + * + * Depends on API functions: + * pthread_once() + * pthread_create() + * pthread_testcancel() + * pthread_cancel() + * pthread_once() + */ + +//#define ASSERT_TRACE + +#include "test.h" + +#define NUM_THREADS OS_MAX_SIMUL_THREADS / 5 /* Targeting each once control */ +#define NUM_ONCE 5 + + +static pthread_once_t o = PTHREAD_ONCE_INIT; +static pthread_once_t once[NUM_ONCE]; + +typedef struct + { + int i; + int null; + pte_osMutexHandle cs; + } sharedInt_t; + +static sharedInt_t numOnce = {0, 0, 0}; +static sharedInt_t numThreads = {0, 0, 0}; + +static void +myfunc(void) +{ + + pte_osMutexLock(numOnce.cs); + numOnce.i++; + assert(numOnce.i > 0); + pte_osMutexUnlock(numOnce.cs); + + /* Simulate slow once routine so that following threads pile up behind it */ + phal_thread_sleep(10); + /* test for cancelation late so we're sure to have waiters. */ + pthread_testcancel(); +} + +static void * +mythread(void * arg) +{ + + /* + * Cancel every thread. These threads are deferred cancelable only, so + * only the thread performing the once routine (my_func) will see it (there are + * no other cancelation points here). The result will be that every thread + * eventually cancels only when it becomes the new once thread. + */ + assert(pthread_cancel(pthread_self()) == 0); + assert(pthread_once(&once[(int) arg], myfunc) == 0); + pte_osMutexLock(numThreads.cs); + numThreads.i++; + pte_osMutexUnlock(numThreads.cs); + + return 0; +} + +int pthread_test_once3() +{ + pthread_t t[NUM_THREADS][NUM_ONCE]; + int i, j; + pthread_once_t onceinit = PTHREAD_ONCE_INIT; + + numOnce.i = 0; + numThreads.i = 0; + + o = onceinit; + + pte_osMutexCreate(&numThreads.cs); + pte_osMutexCreate(&numOnce.cs); + + + for (j = 0; j < NUM_ONCE; j++) + { + once[j] = o; + + for (i = 0; i < NUM_THREADS; i++) + { + assert(pthread_create(&t[i][j], NULL, mythread, (void *) j) == 0); + } + } + + for (j = 0; j < NUM_ONCE; j++) + for (i = 0; i < NUM_THREADS; i++) + if (pthread_join(t[i][j], NULL) != 0) + assert(0); // Join failed for [thread,once] + + /* + * All threads will cancel, none will return normally from + * pthread_once and so numThreads should never be incremented. However, + * numOnce should be incremented by every thread (NUM_THREADS*NUM_ONCE). + */ + assert(numOnce.i == NUM_ONCE * NUM_THREADS); + assert(numThreads.i == 0); + + pte_osMutexDelete(numOnce.cs); + pte_osMutexDelete(numThreads.cs); + + return 0; +} diff --git a/pthread/tests/once4.c b/pthread/tests/once4.c new file mode 100644 index 00000000..cd736bbf --- /dev/null +++ b/pthread/tests/once4.c @@ -0,0 +1,188 @@ +/* + * once4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create several pthread_once objects and channel several threads + * through each. Make the init_routine cancelable and cancel them + * waiters waiting. Vary the priorities. + * + * Depends on API functions: + * pthread_once() + * pthread_create() + * pthread_testcancel() + * pthread_cancel() + * pthread_once() + */ + +#include "test.h" + +#define NUM_THREADS OS_MAX_SIMUL_THREADS / 5 /* Targeting each once control */ +#define NUM_ONCE 5 + +static pthread_once_t o = PTHREAD_ONCE_INIT; +static pthread_once_t once[NUM_ONCE]; + +typedef struct + { + int i; + int null; + pte_osMutexHandle cs; + } sharedInt_t; + +static sharedInt_t numOnce = {0, 0}; +static sharedInt_t numThreads = {0, 0}; + +typedef struct + { + int threadnum; + int oncenum; + int myPrio; +// HANDLE w32Thread; + } bag_t; + +static bag_t threadbag[NUM_THREADS][NUM_ONCE]; + +//static CRITICAL_SECTION print_lock; + +static void +mycleanupfunc(void * arg) +{ + +} + +static void +myinitfunc(void) +{ + + pte_osMutexLock(numOnce.cs); + numOnce.i++; + pte_osMutexUnlock(numOnce.cs); + + /* Simulate slow once routine so that following threads pile up behind it */ + phal_thread_sleep(10); + /* test for cancelation late so we're sure to have waiters. */ + pthread_testcancel(); +} + +static void * +mythread(void * arg) +{ + bag_t * bag = (bag_t *) arg; + struct sched_param param; + + /* + * Cancel every thread. These threads are deferred cancelable only, so + * only the thread performing the init_routine will see it (there are + * no other cancelation points here). The result will be that every thread + * eventually cancels only when it becomes the new initter. + */ + pthread_t self = pthread_self(); +// bag->w32Thread = pthread_getw32threadhandle_np(self); + /* + * Set priority between -2 and 2 inclusive. + */ + bag->myPrio = (bag->threadnum % 5) - 2; + param.sched_priority = bag->myPrio; + pthread_setschedparam(self, SCHED_OTHER, ¶m); + + /* Trigger a cancellation at the next cancellation point in this thread */ + pthread_cancel(self); + pthread_cleanup_push(mycleanupfunc, arg); + assert(pthread_once(&once[bag->oncenum], myinitfunc) == 0); + pthread_cleanup_pop(1); + + pte_osMutexLock(numThreads.cs); + numThreads.i++; + pte_osMutexUnlock(numThreads.cs); + return 0; +} + +int pthread_test_once4() +{ + pthread_t t[NUM_THREADS][NUM_ONCE]; + int i, j; + + numOnce.i = 0; + numThreads.i = 0; + +// pte_osMutexCreate(&print_lock); +// pte_osMutexCreate(&numThreads.cs); +// pte_osMutexCreate(&numOnce.cs); + + /* + * Set the priority class to realtime - otherwise normal + * Windows random priority boosting will obscure any problems. + */ + //SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); + /* Set main thread to lower prio than threads */ + //SetThreadPriority(GetCurrentThread(), -2); + + for (j = 0; j < NUM_ONCE; j++) + { + once[j] = o; + + for (i = 0; i < NUM_THREADS; i++) + { + bag_t * bag = &threadbag[i][j]; + bag->threadnum = i; + bag->oncenum = j; + assert(pthread_create(&t[i][j], NULL, mythread, (void *) bag) == 0); + } + } + + for (j = 0; j < NUM_ONCE; j++) + for (i = 0; i < NUM_THREADS; i++) + if (pthread_join(t[i][j], NULL) != 0) + assert(0); //Join failed for [thread,once] + + /* + * All threads will cancel, none will return normally from + * pthread_once and so numThreads should never be incremented. However, + * numOnce should be incremented by every thread (NUM_THREADS*NUM_ONCE). + */ + assert(numOnce.i == NUM_ONCE * NUM_THREADS); + assert(numThreads.i == 0); + +// pte_osMutexDelete(&numOnce.cs); +// pte_osMutexDelete(&numThreads.cs); +// pte_osMutexDelete(&print_lock); + + return 0; +} diff --git a/pthread/tests/priority1.c b/pthread/tests/priority1.c new file mode 100644 index 00000000..1b7f493c --- /dev/null +++ b/pthread/tests/priority1.c @@ -0,0 +1,131 @@ +/* + * File: priority1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test thread priority explicit setting using thread attribute. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +enum +{ + PTW32TEST_THREAD_INIT_PRIO = 0, + PTW32TEST_MAXPRIORITIES = 512 +}; + +/* +static int minPrio; +static int maxPrio; +static int validPriorities[PTW32TEST_MAXPRIORITIES]; +*/ + +static int pthreadPrio; + +static void * +func(void * arg) +{ + int policy; + struct sched_param param; + pthread_t threadID = pthread_self(); + + assert(pthread_getschedparam(threadID, &policy, ¶m) == 0); + assert(policy == SCHED_OTHER); + assert(param.sched_priority == (int) pthreadPrio); + + assert(phal_thread_priority(phal_thread_handle()) == param.sched_priority); + + + return (void *) 0; +} + +int pthread_test_priority1() +{ + pthread_t t; + pthread_attr_t attr; + void * result = NULL; + struct sched_param param; + + assert(pthread_attr_init(&attr) == 0); + assert(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0); + + param.sched_priority = sched_get_priority_min(SCHED_OTHER) + 1; + pthreadPrio = sched_get_priority_min(SCHED_OTHER) + 1; + assert(pthread_attr_setschedparam(&attr, ¶m) == 0); + + assert(pthread_create(&t, &attr, func, (void *) &attr) == 0); + assert(pthread_join(t, &result) == 0); + + return 0; +} diff --git a/pthread/tests/priority2.c b/pthread/tests/priority2.c new file mode 100644 index 00000000..805cf55b --- /dev/null +++ b/pthread/tests/priority2.c @@ -0,0 +1,156 @@ +/* + * File: priority2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test thread priority setting after creation. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +enum +{ + PTW32TEST_THREAD_INIT_PRIO = 0, + PTW32TEST_MAXPRIORITIES = 512 +}; + +static pthread_barrier_t startBarrier, endBarrier; + +static void * func(void * arg) +{ + int policy; + int result; + struct sched_param param; + + result = pthread_barrier_wait(&startBarrier); + assert(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD); + assert(pthread_getschedparam(pthread_self(), &policy, ¶m) == 0); + assert(policy == SCHED_OTHER); + result = pthread_barrier_wait(&endBarrier); + assert(result == 0 || result == PTHREAD_BARRIER_SERIAL_THREAD); + + assert(pte_osThreadGetPriority(pte_osThreadGetHandle()) == param.sched_priority); + + return (void *) param.sched_priority; +} + + + +int pthread_test_priority2() +{ + pthread_t t; + void * result = NULL; + int result2; + struct sched_param param; + + + /* + assert(pthread_create(&t, NULL, getValidPriorities, NULL) == 0); + assert(pthread_join(t, &result) == 0); + */ + + assert(pthread_barrier_init(&startBarrier, NULL, 2) == 0); + assert(pthread_barrier_init(&endBarrier, NULL, 2) == 0); + + /* Set the thread's priority to a known initial value. + * If the new priority is invalid then the threads priority + * is unchanged from the previous value. + */ + /* + SetThreadPriority(pthread_getw32threadhandle_np(pthread_self()), + PTW32TEST_THREAD_INIT_PRIO); + */ + for (param.sched_priority = pte_osThreadGetMinPriority(); + param.sched_priority <= pte_osThreadGetMaxPriority(); + param.sched_priority++) + { + assert(pthread_create(&t, NULL, func, NULL) == 0); + assert(pthread_setschedparam(t, SCHED_OTHER, ¶m) == 0); + result2 = pthread_barrier_wait(&startBarrier); + assert(result2 == 0 || result2 == PTHREAD_BARRIER_SERIAL_THREAD); + result2 = pthread_barrier_wait(&endBarrier); + assert(result2 == 0 || result2 == PTHREAD_BARRIER_SERIAL_THREAD); + +// assert(GetThreadPriority(pthread_getw32threadhandle_np(t)) == +// validPriorities[param.sched_priority+(PTW32TEST_MAXPRIORITIES/2)]); + + pthread_join(t, &result); + assert(param.sched_priority == (int)result); + } + + assert(pthread_barrier_destroy(&startBarrier) == 0); + assert(pthread_barrier_destroy(&endBarrier) == 0); + + return 0; +} diff --git a/pthread/tests/reuse1.c b/pthread/tests/reuse1.c new file mode 100644 index 00000000..1cec8bdb --- /dev/null +++ b/pthread/tests/reuse1.c @@ -0,0 +1,130 @@ +/* + * File: reuse1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Confirm that thread reuse works for joined threads. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +enum +{ + NUMTHREADS = 50 +}; + +static int washere = 0; + +static void * func(void * arg) +{ + washere = 1; + return arg; +} + +int pthread_test_reuse1() +{ + pthread_t t, + last_t; + pthread_attr_t attr; + void * result = NULL; + int i; + + assert(pthread_attr_init(&attr) == 0);; + assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); + + washere = 0; + assert(pthread_create(&t, &attr, func, NULL) == 0); + assert(pthread_join(t, &result) == 0);; + assert(result == 0); + assert(washere == 1); + last_t = t; + + for (i = 1; i < NUMTHREADS; i++) + { + washere = 0; + assert(pthread_create(&t, &attr, func, (void *) i) == 0); + pthread_join(t, &result); + assert((int) result == i); + assert(washere == 1); + /* thread IDs should be unique */ + assert(!pthread_equal(t, last_t)); + /* thread struct pointers should be the same */ + assert(t == last_t); + /* TODO: thread handle reuse counter should be different by one */ + //assert(t.x == last_t.x+1); + last_t = t; + } + + return 0; +} diff --git a/pthread/tests/reuse2.c b/pthread/tests/reuse2.c new file mode 100644 index 00000000..151d72a5 --- /dev/null +++ b/pthread/tests/reuse2.c @@ -0,0 +1,170 @@ +/* + * File: reuse2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test that thread reuse works for detached threads. + * - Analyse thread struct reuse. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - This test is implementation specific + * because it uses knowledge of internals that should be + * opaque to an application. + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#include "implement.h" + +/* + */ + +enum +{ + NUMTHREADS = 100 +}; + + +static int done = 0; + +static void * func(void * arg) +{ + sched_yield(); + + PTE_ATOMIC_INCREMENT(&done); + + return (void *) 0; +} + +int pthread_test_reuse2() +{ + pthread_t t[NUMTHREADS]; + pthread_attr_t attr; + int i; + unsigned int notUnique = 0, + totalHandles = 0, + reuseMax = 0, + reuseMin = NUMTHREADS; + + assert(pthread_attr_init(&attr) == 0); + assert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); + + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&t[i], &attr, func, NULL) == 0); + } + + while (NUMTHREADS > PTE_ATOMIC_EXCHANGE_ADD(&done, 0L)) + phal_thread_sleep(100); + + phal_thread_sleep(100); + + /* + * Analyse reuse by computing min and max number of times pthread_create() + * returned the same pthread_t value. + */ + for (i = 0; i < NUMTHREADS; i++) + { + if (t[i] != NULL) + { + unsigned int j, thisMax; + + thisMax = t[i].x; + + for (j = i+1; j < NUMTHREADS; j++) + if (t[i].p == t[j].p) + { + if (t[i].x == t[j].x) + notUnique++; + if (thisMax < t[j].x) + thisMax = t[j].x; + t[j].p = NULL; + } + + if (reuseMin > thisMax) + reuseMin = thisMax; + + if (reuseMax < thisMax) + reuseMax = thisMax; + } + } + + for (i = 0; i < NUMTHREADS; i++) + if (t[i] != NULL) + totalHandles++; + + /* + * pthread_t reuse counts start at 0, so we need to add 1 + * to the max and min values derived above. + */ + + return 0; +} diff --git a/pthread/tests/rwlock1.c b/pthread/tests/rwlock1.c new file mode 100644 index 00000000..f8739cc1 --- /dev/null +++ b/pthread/tests/rwlock1.c @@ -0,0 +1,68 @@ +/* + * rwlock1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create a simple rwlock object and then destroy it. + * + * Depends on API functions: + * pthread_rwlock_init() + * pthread_rwlock_destroy() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock = NULL; + +int pthread_test_rwlock1() +{ + rwlock = NULL; + + assert(rwlock == NULL); + + assert(pthread_rwlock_init(&rwlock, NULL) == 0); + + assert(rwlock != NULL); + + assert(pthread_rwlock_destroy(&rwlock) == 0); + + assert(rwlock == NULL); + + return 0; +} diff --git a/pthread/tests/rwlock2.c b/pthread/tests/rwlock2.c new file mode 100644 index 00000000..7f9c829a --- /dev/null +++ b/pthread/tests/rwlock2.c @@ -0,0 +1,73 @@ +/* + * rwlock2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, lock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + +int pthread_test_rwlock2() +{ + rwlock = PTHREAD_RWLOCK_INITIALIZER; + + assert(rwlock == PTHREAD_RWLOCK_INITIALIZER); + + assert(pthread_rwlock_rdlock(&rwlock) == 0); + + assert(rwlock != PTHREAD_RWLOCK_INITIALIZER); + + assert(rwlock != NULL); + + assert(pthread_rwlock_unlock(&rwlock) == 0); + + assert(pthread_rwlock_destroy(&rwlock) == 0); + + assert(rwlock == NULL); + + return 0; +} diff --git a/pthread/tests/rwlock2_t.c b/pthread/tests/rwlock2_t.c new file mode 100644 index 00000000..27f0148c --- /dev/null +++ b/pthread/tests/rwlock2_t.c @@ -0,0 +1,87 @@ +/* + * rwlock2_t.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, timed-lock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_timedrdlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; + +int pthread_test_rwlock2t() +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + rwlock = PTHREAD_RWLOCK_INITIALIZER; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(rwlock == PTHREAD_RWLOCK_INITIALIZER); + + assert(pthread_rwlock_timedrdlock(&rwlock, &abstime) == 0); + + assert(rwlock != PTHREAD_RWLOCK_INITIALIZER); + + assert(rwlock != NULL); + + assert(pthread_rwlock_unlock(&rwlock) == 0); + + assert(pthread_rwlock_destroy(&rwlock) == 0); + + assert(rwlock == NULL); + + return 0; +} diff --git a/pthread/tests/rwlock3.c b/pthread/tests/rwlock3.c new file mode 100644 index 00000000..f385db00 --- /dev/null +++ b/pthread/tests/rwlock3.c @@ -0,0 +1,87 @@ +/* + * rwlock3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, wrlock it, trywrlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_wrlock() + * pthread_rwlock_trywrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); + + washere = 1; + + return 0; +} + +int pthread_test_rwlock3() +{ + pthread_t t; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + assert(pthread_rwlock_wrlock(&rwlock1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + phal_thread_sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + assert(pthread_join(t, NULL) == 0); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock3_t.c b/pthread/tests/rwlock3_t.c new file mode 100644 index 00000000..126aef74 --- /dev/null +++ b/pthread/tests/rwlock3_t.c @@ -0,0 +1,100 @@ +/* + * rwlock3_t.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, timed-wrlock it, trywrlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_timedwrlock() + * pthread_rwlock_trywrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); + + washere = 1; + + return 0; +} + +int pthread_test_rwlock3t() +{ + pthread_t t; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(pthread_rwlock_timedwrlock(&rwlock1, &abstime) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + phal_thread_sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock4.c b/pthread/tests/rwlock4.c new file mode 100644 index 00000000..14c7e003 --- /dev/null +++ b/pthread/tests/rwlock4.c @@ -0,0 +1,87 @@ +/* + * rwlock4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, rdlock it, trywrlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_trywrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); + + washere = 1; + + return 0; +} + +int pthread_test_rwlock4() +{ + pthread_t t; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + assert(pthread_rwlock_rdlock(&rwlock1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + phal_thread_sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock4_t.c b/pthread/tests/rwlock4_t.c new file mode 100644 index 00000000..d2ab48ba --- /dev/null +++ b/pthread/tests/rwlock4_t.c @@ -0,0 +1,100 @@ +/* + * rwlock4_t.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, timed-rdlock it, trywrlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_timedrdlock() + * pthread_rwlock_trywrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_rwlock_trywrlock(&rwlock1) == EBUSY); + + washere = 1; + + return 0; +} + +int pthread_test_rwlock4t() +{ + pthread_t t; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + phal_thread_sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock5.c b/pthread/tests/rwlock5.c new file mode 100644 index 00000000..6eb8aede --- /dev/null +++ b/pthread/tests/rwlock5.c @@ -0,0 +1,89 @@ +/* + * rwlock5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, rdlock it, tryrdlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_tryrdlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_rwlock_tryrdlock(&rwlock1) == 0); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + washere = 1; + + return 0; +} + +int pthread_test_rwlock5() +{ + pthread_t t; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + assert(pthread_rwlock_rdlock(&rwlock1) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + phal_thread_sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock5_t.c b/pthread/tests/rwlock5_t.c new file mode 100644 index 00000000..eb89f50c --- /dev/null +++ b/pthread/tests/rwlock5_t.c @@ -0,0 +1,105 @@ +/* + * rwlock5_t.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static rwlock object, timed-rdlock it, tryrdlock it, + * and then unlock it again. + * + * Depends on API functions: + * pthread_rwlock_timedrdlock() + * pthread_rwlock_tryrdlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_rwlock_tryrdlock(&rwlock1) == 0); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + washere = 1; + + return 0; +} + +int pthread_test_rwlock5t() +{ + pthread_t t; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + washere = 0; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + phal_thread_sleep(2000); + + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + assert(washere == 1); + + assert(pthread_join(t,NULL) == 0); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock6.c b/pthread/tests/rwlock6.c new file mode 100644 index 00000000..20a7ad80 --- /dev/null +++ b/pthread/tests/rwlock6.c @@ -0,0 +1,110 @@ +/* + * rwlock6.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Check writer and reader locking + * + * Depends on API functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_wrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int bankAccount = 0; + +static void * wrfunc(void * arg) +{ + int ba; + + assert(pthread_rwlock_wrlock(&rwlock1) == 0); + phal_thread_sleep(2000); + bankAccount += 10; + ba = bankAccount; + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + return ((void *) ba); +} + +static void * rdfunc(void * arg) +{ + int ba; + + assert(pthread_rwlock_rdlock(&rwlock1) == 0); + ba = bankAccount; + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + return ((void *) ba); +} + +int pthread_test_rwlock6() +{ + pthread_t wrt1; + pthread_t wrt2; + pthread_t rdt; + int wr1Result = 0; + int wr2Result = 0; + int rdResult = 0; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + bankAccount = 0; + + assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0); + phal_thread_sleep(500); + assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0); + phal_thread_sleep(500); + assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0); + + assert(pthread_join(wrt1, (void **) &wr1Result) == 0); + assert(pthread_join(rdt, (void **) &rdResult) == 0); + assert(pthread_join(wrt2, (void **) &wr2Result) == 0); + + assert(wr1Result == 10); + assert(rdResult == 10); + assert(wr2Result == 20); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock6_t.c b/pthread/tests/rwlock6_t.c new file mode 100644 index 00000000..7e1d3dfe --- /dev/null +++ b/pthread/tests/rwlock6_t.c @@ -0,0 +1,137 @@ +/* + * rwlock6_t.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Check writer and reader locking with reader timeouts + * + * Depends on API functions: + * pthread_rwlock_timedrdlock() + * pthread_rwlock_wrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int bankAccount = 0; + +static void * wrfunc(void * arg) +{ + assert(pthread_rwlock_wrlock(&rwlock1) == 0); + phal_thread_sleep(2000); + bankAccount += 10; + assert(pthread_rwlock_unlock(&rwlock1) == 0); + + return ((void *) bankAccount); +} + +static void * rdfunc(void * arg) +{ + int ba = -1; + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + + if ((int) arg == 1) + { + abstime.tv_sec += 1; + assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == ETIMEDOUT); + ba = 0; + } + else if ((int) arg == 2) + { + abstime.tv_sec += 3; + assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == 0); + ba = bankAccount; + assert(pthread_rwlock_unlock(&rwlock1) == 0); + } + + return ((void *) ba); +} + +int pthread_test_rwlock6t() +{ + pthread_t wrt1; + pthread_t wrt2; + pthread_t rdt1; + pthread_t rdt2; + int wr1Result = 0; + int wr2Result = 0; + int rd1Result = 0; + int rd2Result = 0; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + bankAccount = 0; + + assert(pthread_create(&wrt1, NULL, wrfunc, NULL) == 0); + phal_thread_sleep(500); + assert(pthread_create(&rdt1, NULL, rdfunc, (void *) 1) == 0); + phal_thread_sleep(500); + assert(pthread_create(&wrt2, NULL, wrfunc, NULL) == 0); + phal_thread_sleep(500); + assert(pthread_create(&rdt2, NULL, rdfunc, (void *) 2) == 0); + + assert(pthread_join(wrt1, (void **) &wr1Result) == 0); + assert(pthread_join(rdt1, (void **) &rd1Result) == 0); + assert(pthread_join(wrt2, (void **) &wr2Result) == 0); + assert(pthread_join(rdt2, (void **) &rd2Result) == 0); + + assert(wr1Result == 10); + assert(rd1Result == 0); + assert(wr2Result == 20); + assert(rd2Result == 20); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} + + diff --git a/pthread/tests/rwlock6_t2.c b/pthread/tests/rwlock6_t2.c new file mode 100644 index 00000000..a243dcae --- /dev/null +++ b/pthread/tests/rwlock6_t2.c @@ -0,0 +1,131 @@ +/* + * rwlock6_t2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Check writer and reader timeouts. + * + * Depends on API functions: + * pthread_rwlock_timedrdlock() + * pthread_rwlock_timedwrlock() + * pthread_rwlock_unlock() + */ + +#include "test.h" + + +static pthread_rwlock_t rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + +static int bankAccount = 0; +struct timespec abstime = + { + 0, 0 + }; + +static void * wrfunc(void * arg) +{ + int result; + + result = pthread_rwlock_timedwrlock(&rwlock1, &abstime); + if ((int) arg == 1) + { + assert(result == 0); + phal_thread_sleep(2000); + bankAccount += 10; + assert(pthread_rwlock_unlock(&rwlock1) == 0); + return ((void *) bankAccount); + } + else if ((int) arg == 2) + { + assert(result == ETIMEDOUT); + return ((void *) 100); + } + + return ((void *) -1); +} + +static void * rdfunc(void * arg) +{ + int ba = 0; + + assert(pthread_rwlock_timedrdlock(&rwlock1, &abstime) == ETIMEDOUT); + + return ((void *) ba); +} + +int pthread_test_rwlock6t2() +{ + pthread_t wrt1; + pthread_t wrt2; + pthread_t rdt; + int wr1Result = 0; + int wr2Result = 0; + int rdResult = 0; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + rwlock1 = PTHREAD_RWLOCK_INITIALIZER; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 1; + + bankAccount = 0; + + assert(pthread_create(&wrt1, NULL, wrfunc, (void *) 1) == 0); + phal_thread_sleep(100); + assert(pthread_create(&rdt, NULL, rdfunc, NULL) == 0); + phal_thread_sleep(100); + assert(pthread_create(&wrt2, NULL, wrfunc, (void *) 2) == 0); + + assert(pthread_join(wrt1, (void **) &wr1Result) == 0); + assert(pthread_join(rdt, (void **) &rdResult) == 0); + assert(pthread_join(wrt2, (void **) &wr2Result) == 0); + + assert(wr1Result == 10); + assert(rdResult == 0); + assert(wr2Result == 100); + + assert(pthread_rwlock_destroy(&rwlock1) == 0); + + return 0; +} diff --git a/pthread/tests/rwlock7.c b/pthread/tests/rwlock7.c new file mode 100644 index 00000000..3d34d7ac --- /dev/null +++ b/pthread/tests/rwlock7.c @@ -0,0 +1,188 @@ +/* + * rwlock7.c + * + * Hammer on a bunch of rwlocks to test robustness and fairness. + * Printed stats should be roughly even for each thread. + */ + +#include "test.h" + +#ifdef __GNUC__ +#include +#endif + +#define THREADS 5 +#define DATASIZE 7 +#define ITERATIONS 100000 + +/* + * Keep statistics for each thread. + */ +typedef struct thread_tag + { + int thread_num; + pthread_t thread_id; + int updates; + int reads; + int changed; + unsigned int seed; + } thread_t; + +/* + * Read-write lock and shared data + */ +typedef struct data_tag + { + pthread_rwlock_t lock; + int data; + int updates; + } data_t; + +static thread_t threads[THREADS]; +static data_t data[DATASIZE]; + +/* + * Thread start routine that uses read-write locks + */ +static void *thread_routine (void *arg) +{ + thread_t *self = (thread_t*)arg; + int iteration; + int element = 0; + int interval = 1 + rand() % 71; + + self->changed = 0; + + for (iteration = 0; iteration < ITERATIONS; iteration++) + { + /* + if (iteration % (ITERATIONS / 10) == 0) + { + putchar('.'); + fflush(stdout); + } + */ + /* + * Each "self->interval" iterations, perform an + * update operation (write lock instead of read + * lock). + */ + if ((iteration % interval) == 0) + { + assert(pthread_rwlock_wrlock (&data[element].lock) == 0); + data[element].data = self->thread_num; + data[element].updates++; + self->updates++; + interval = 1 + rand () % 71; + assert(pthread_rwlock_unlock (&data[element].lock) == 0); + } + else + { + /* + * Look at the current data element to see whether + * the current thread last updated it. Count the + * times, to report later. + */ + assert(pthread_rwlock_rdlock (&data[element].lock) == 0); + + self->reads++; + + if (data[element].data != self->thread_num) + { + self->changed++; + interval = 1 + self->changed % 71; + } + + assert(pthread_rwlock_unlock (&data[element].lock) == 0); + } + + element = (element + 1) % DATASIZE; + + } + + return NULL; +} + +int pthread_test_rwlock7() +{ + int count; + int data_count; + int thread_updates = 0; + int data_updates = 0; + + struct timeval currSysTime1; + struct timeval currSysTime2; + + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) + { + data[data_count].data = 0; + data[data_count].updates = 0; + + assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); + } + + gettimeofday(&currSysTime1, NULL); + + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) + { + threads[count].thread_num = count; + threads[count].updates = 0; + threads[count].reads = 0; + threads[count].seed = 1 + rand() % 71; + + assert(pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]) == 0); + } + + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) + { + assert(pthread_join (threads[count].thread_id, NULL) == 0); + } + + /* + putchar('\n'); + fflush(stdout); + */ + + for (count = 0; count < THREADS; count++) + { + } + + /* + putchar('\n'); + fflush(stdout); + */ + + for (count = 0; count < THREADS; count++) + { + thread_updates += threads[count].updates; + } + + /* + putchar('\n'); + fflush(stdout); + */ + + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) + { + data_updates += data[data_count].updates; + assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); + } + + gettimeofday(&currSysTime2, NULL); + + return 0; +} diff --git a/pthread/tests/rwlock8.c b/pthread/tests/rwlock8.c new file mode 100644 index 00000000..29c68e99 --- /dev/null +++ b/pthread/tests/rwlock8.c @@ -0,0 +1,178 @@ +/* + * rwlock8.c + * + * Hammer on a bunch of rwlocks to test robustness and fairness. + * Printed stats should be roughly even for each thread. + * + * Yield during each access to exercise lock contention code paths + * more than rwlock7.c does (particularly on uni-processor systems). + */ + +#include "test.h" + +#ifdef __GNUC__ +#include +#endif + +#define THREADS 5 +#define DATASIZE 7 +#define ITERATIONS 10000 + +/* + * Keep statistics for each thread. + */ +typedef struct thread_tag + { + int thread_num; + pthread_t thread_id; + int updates; + int reads; + int changed; + unsigned int seed; + } thread_t; + +/* + * Read-write lock and shared data + */ +typedef struct data_tag + { + pthread_rwlock_t lock; + int data; + int updates; + } data_t; + +static thread_t threads[THREADS]; +static data_t data[DATASIZE]; + +/* + * Thread start routine that uses read-write locks + */ +static void *thread_routine (void *arg) +{ + thread_t *self = (thread_t*)arg; + int iteration; + int element = 0; + int interval = 1 + rand() % 71; + + self->changed = 0; + + for (iteration = 0; iteration < ITERATIONS; iteration++) + { + /* + if (iteration % (ITERATIONS / 10) == 0) + { + putchar('.'); + fflush(stdout); + } + */ + /* + * Each "self->interval" iterations, perform an + * update operation (write lock instead of read + * lock). + */ + if ((iteration % interval) == 0) + { + assert(pthread_rwlock_wrlock (&data[element].lock) == 0); + data[element].data = self->thread_num; + data[element].updates++; + self->updates++; + interval = 1 + rand() % 71; + sched_yield(); + assert(pthread_rwlock_unlock (&data[element].lock) == 0); + } + else + { + /* + * Look at the current data element to see whether + * the current thread last updated it. Count the + * times, to report later. + */ + assert(pthread_rwlock_rdlock (&data[element].lock) == 0); + + self->reads++; + + if (data[element].data != self->thread_num) + { + self->changed++; + interval = 1 + self->changed % 71; + } + + sched_yield(); + + assert(pthread_rwlock_unlock (&data[element].lock) == 0); + } + + element = (element + 1) % DATASIZE; + + } + + return NULL; +} + +int pthread_test_rwlock8() +{ + int count; + int data_count; + int thread_updates = 0; + int data_updates = 0; + + struct timeval currSysTime1; + struct timeval currSysTime2; + + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) + { + data[data_count].data = 0; + data[data_count].updates = 0; + + assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); + } + + gettimeofday(&currSysTime1, NULL); + + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) + { + threads[count].thread_num = count; + threads[count].updates = 0; + threads[count].reads = 0; + threads[count].seed = 1 + rand() % 71; + + assert(pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]) == 0); + } + + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) + { + assert(pthread_join (threads[count].thread_id, NULL) == 0); + } + for (count = 0; count < THREADS; count++) + { + thread_updates += threads[count].updates; + } + /* + putchar('\n'); + fflush(stdout); + */ + + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) + { + data_updates += data[data_count].updates; + assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); + } + + gettimeofday(&currSysTime2, NULL); + + return 0; +} diff --git a/pthread/tests/self1.c b/pthread/tests/self1.c new file mode 100644 index 00000000..13ceaedd --- /dev/null +++ b/pthread/tests/self1.c @@ -0,0 +1,76 @@ +/* + * self1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test for pthread_self(). + * + * Depends on API functions: + * pthread_self() + * + * Implicitly depends on: + * pthread_getspecific() + * pthread_setspecific() + */ + +#include + +#include "test.h" + +int pthread_test_self1() +{ + /* + * This should always succeed unless the system has no + * resources (memory) left. + */ + pthread_t self; + +#ifdef PTW32_STATIC_LIB +// pthread_win32_process_attach_np(); +#endif + + self = pthread_self(); + + assert(self != NULL); + +#ifdef PTW32_STATIC_LIB +// pthread_win32_process_detach_np(); +#endif + return 0; +} diff --git a/pthread/tests/self2.c b/pthread/tests/self2.c new file mode 100644 index 00000000..9bd1e248 --- /dev/null +++ b/pthread/tests/self2.c @@ -0,0 +1,83 @@ +/* + * self2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test for pthread_self(). + * + * Depends on API functions: + * pthread_create() + * pthread_self() + * + * Implicitly depends on: + * pthread_getspecific() + * pthread_setspecific() + */ + +#include +#include + +#include "test.h" +//#include + +static pthread_t me; + +static void * +entry(void * arg) +{ + me = pthread_self(); + + return arg; +} + +int pthread_test_self2() +{ + pthread_t t; + + assert(pthread_create(&t, NULL, entry, NULL) == 0); + + phal_thread_sleep(100); + + assert(pthread_equal(t, me) != 0); + + assert(pthread_join(t,NULL) == 0); + + /* Success. */ + return 0; +} diff --git a/pthread/tests/semaphore1.c b/pthread/tests/semaphore1.c new file mode 100644 index 00000000..3dd85ee4 --- /dev/null +++ b/pthread/tests/semaphore1.c @@ -0,0 +1,139 @@ +/* + * File: semaphore1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verify trywait() returns -1 and sets EAGAIN. + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +static void * +thr(void * arg) +{ + sem_t s; + int result; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + + assert((result = sem_trywait(&s)) == -1); + + if ( result == -1 ) + { + int err = errno; + assert(err == EAGAIN); + } + + assert((result = sem_post(&s)) == 0); + + assert((result = sem_trywait(&s)) == 0); + + assert(sem_post(&s) == 0); + + assert(sem_destroy(&s) == 0); + + return 0; +} + + +int pthread_test_semaphore1(void) +{ + pthread_t t; + sem_t s; + int result; + + assert(pthread_create(&t, NULL, thr, NULL) == 0); + assert(pthread_join(t, (void **)&result) == 0); + assert(result == 0); + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + + assert((result = sem_trywait(&s)) == -1); + + if ( result == -1 ) + { + int err = errno; + assert(err == EAGAIN); + } + + assert((result = sem_post(&s)) == 0); + + assert((result = sem_trywait(&s)) == 0); + + assert(sem_post(&s) == 0); + + assert(sem_destroy(&s) == 0); + return 0; +} + diff --git a/pthread/tests/semaphore2.c b/pthread/tests/semaphore2.c new file mode 100644 index 00000000..a9c622ee --- /dev/null +++ b/pthread/tests/semaphore2.c @@ -0,0 +1,112 @@ +/* + * File: semaphore2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verify sem_getvalue returns the correct value. + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#define MAX_COUNT 100 + +int pthread_test_semaphore2(void) +{ + sem_t s; + int value = 0; + int i; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, MAX_COUNT) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == MAX_COUNT); + + for (i = MAX_COUNT - 1; i >= 0; i--) + { + assert(sem_wait(&s) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == i); + } + + for (i = 1; i <= MAX_COUNT; i++) + { + assert(sem_post(&s) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == i); + } + + assert(sem_destroy(&s) == 0); + + return 0; +} + diff --git a/pthread/tests/semaphore3.c b/pthread/tests/semaphore3.c new file mode 100644 index 00000000..c6b5f11d --- /dev/null +++ b/pthread/tests/semaphore3.c @@ -0,0 +1,129 @@ +/* + * File: semaphore3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verify sem_getvalue returns the correct number of waiters. + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#define MAX_COUNT 5 + +static sem_t s; + +static void * +thr (void * arg) +{ + assert(sem_wait(&s) == 0); + assert(pthread_detach(pthread_self()) == 0); + return NULL; +} + +int pthread_test_semaphore3(void) +{ + int value = 0; + int i; + pthread_t t[MAX_COUNT+1]; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == 0); + + for (i = 1; i <= MAX_COUNT; i++) + { + assert(pthread_create(&t[i], NULL, thr, NULL) == 0); + do + { + sched_yield(); + assert(sem_getvalue(&s, &value) == 0); + } + while (value != -i); + assert(-value == i); + } + + for (i = MAX_COUNT - 1; i >= 0; i--) + { + assert(sem_post(&s) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(-value == i); + } + + phal_thread_sleep(1000); + + assert(sem_destroy(&s) == 0); + + return 0; +} + diff --git a/pthread/tests/semaphore4.c b/pthread/tests/semaphore4.c new file mode 100644 index 00000000..424e652b --- /dev/null +++ b/pthread/tests/semaphore4.c @@ -0,0 +1,162 @@ +/* + * File: semaphore4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verify sem_getvalue returns the correct number of waiters + * after threads are cancelled. + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" +#include +#include + +#define MAX_COUNT 16 // OS_MAX_SIMUL_THREADS + +static sem_t s; + +static void * +thr (void * arg) +{ + + if ((int) arg == 5) + { + // We expect this thread to be cancelled, + // so sem_wait should return EINTR. + assert(sem_wait(&s) == -1); + assert(errno == EINTR); + } + else + { + // Should exit normally + assert(sem_wait(&s) == 0); + } + + return NULL; +} + +int pthread_test_semaphore4(void) +{ + int value = 0; + int i; + pthread_t t[MAX_COUNT+1]; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == 0); + + for (i = 1; i <= MAX_COUNT; i++) + { + assert(pthread_create(&t[i], NULL, thr, (void *)i) == 0); + do + { + sched_yield(); + assert(sem_getvalue(&s, &value) == 0); + } + while (value != -i); + + assert(-value == i); + } + + assert(sem_getvalue(&s, &value) == 0); + assert(-value == MAX_COUNT); + + assert(pthread_cancel(t[5]) == 0); + { + int result; + assert(pthread_join(t[5], (void **) &result) == 0); + } + assert(sem_getvalue(&s, &value) == 0); + + assert(-value == (MAX_COUNT - 1)); + + for (i = MAX_COUNT - 2; i >= 0; i--) + { + assert(sem_post(&s) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(-value == i); + } + + + for (i = 1; i <= MAX_COUNT; i++) + { + if (i != 5) + assert(pthread_join(t[i], NULL) == 0); + } + + assert(sem_destroy(&s) == 0); + + return 0; +} + diff --git a/pthread/tests/semaphore4t.c b/pthread/tests/semaphore4t.c new file mode 100644 index 00000000..4cdc2998 --- /dev/null +++ b/pthread/tests/semaphore4t.c @@ -0,0 +1,151 @@ +/* + * File: semaphore4t.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verify sem_getvalue returns the correct number of waiters + * after threads are cancelled. + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - sem_timedwait cancellation. + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +#define MAX_COUNT 16 // OS_MAX_SIMUL_THREADS + +static sem_t s; + +static void * +thr (void * arg) +{ + if ((int) arg == 5) + { + // We expect this thread to be cancelled, + // so sem_wait should return EINTR. + assert(sem_timedwait(&s,NULL) == -1); + assert(errno == EINTR); + } + else + { + assert(sem_timedwait(&s,NULL) == 0); + } + + return NULL; +} + +int pthread_test_semaphore4t(void) +{ + int value = 0; + int i; + pthread_t t[MAX_COUNT+1]; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == 0); + + for (i = 1; i <= MAX_COUNT; i++) + { + assert(pthread_create(&t[i], NULL, thr, (void *) i) == 0); + do + { + sched_yield(); + assert(sem_getvalue(&s, &value) == 0); + } + while (value != -i); + assert(-value == i); + } + + assert(sem_getvalue(&s, &value) == 0); + assert(-value == MAX_COUNT); + assert(pthread_cancel(t[5]) == 0); + assert(pthread_join(t[5], NULL) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(-value == MAX_COUNT - 1); + + for (i = MAX_COUNT - 2; i >= 0; i--) + { + assert(sem_post(&s) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(-value == i); + } + + for (i = 1; i <= MAX_COUNT; i++) + { + if (i != 5) + assert(pthread_join(t[i], NULL) == 0); + } + + assert(sem_destroy(&s) == 0); + + return 0; +} + diff --git a/pthread/tests/semaphore5.c b/pthread/tests/semaphore5.c new file mode 100644 index 00000000..8954b7d2 --- /dev/null +++ b/pthread/tests/semaphore5.c @@ -0,0 +1,111 @@ +/* + * File: semaphore5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verifies that sem_timedwait returns after timeout. + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +static sem_t s; + +static void * +thr (void * arg) +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + assert_eq(sem_timedwait(&s, &abstime), -1); + assert(errno == ETIMEDOUT); + + return NULL; +} + +int pthread_test_semaphore5(void) +{ + int value = 0; + pthread_t handle; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == 0); + + + assert(pthread_create(&handle, NULL, thr, NULL) == 0); + + assert(pthread_join(handle, NULL) == 0); + + assert(sem_destroy(&s) == 0); + + return 0; +} + diff --git a/pthread/tests/semaphore6.c b/pthread/tests/semaphore6.c new file mode 100644 index 00000000..455fc1ef --- /dev/null +++ b/pthread/tests/semaphore6.c @@ -0,0 +1,121 @@ +/* + * File: semaphore5.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: Verifies that sem_timedwait doesn't return before timeout + * expires + * - + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +static sem_t s; +static int semStatus; + +static void * +thr (void * arg) +{ + struct timespec abstime = + { + 0, 0 + }; + struct timeval currSysTime; + const long long NANOSEC_PER_MILLISEC = 1000000; + + gettimeofday(&currSysTime, NULL); + + abstime.tv_sec = currSysTime.tv_sec; + abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.tv_usec / 1000; + + abstime.tv_sec += 5; + assert(sem_timedwait(&s, &abstime) == -1); + assert(errno == ETIMEDOUT); + + semStatus = 1; + // assert(pthread_detach(pthread_self()) == 0); + return NULL; +} + +int pthread_test_semaphore6(void) +{ + int value = 0; + pthread_t handle; + + assert(sem_init(&s, PTHREAD_PROCESS_PRIVATE, 0) == 0); + assert(sem_getvalue(&s, &value) == 0); + assert(value == 0); + + semStatus = 0; + + assert(pthread_create(&handle, NULL, thr, NULL) == 0); + + phal_thread_sleep(3000); + + /* Make sure that sem_timedwait doesn't return too early */ + assert(semStatus == 0); + + assert(pthread_join(handle, NULL) == 0); + + assert(sem_destroy(&s) == 0); + + return 0; +} + diff --git a/pthread/tests/spin1.c b/pthread/tests/spin1.c new file mode 100644 index 00000000..c400147e --- /dev/null +++ b/pthread/tests/spin1.c @@ -0,0 +1,64 @@ +/* + * spin1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Create a simple spinlock object, lock it, and then unlock it again. + * This is the simplest test of the pthread mutex family that we can do. + * + */ + +#include "test.h" + +static pthread_spinlock_t lock; + +int pthread_test_spin1() +{ + assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); + + assert(pthread_spin_lock(&lock) == 0); + + assert(pthread_spin_unlock(&lock) == 0); + + assert(pthread_spin_destroy(&lock) == 0); + + assert(pthread_spin_lock(&lock) == EINVAL); + + return 0; +} diff --git a/pthread/tests/spin2.c b/pthread/tests/spin2.c new file mode 100644 index 00000000..e412a386 --- /dev/null +++ b/pthread/tests/spin2.c @@ -0,0 +1,80 @@ +/* + * spin2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a spinlock object, lock it, trylock it, + * and then unlock it again. + * + */ + +#include "test.h" + +static pthread_spinlock_t lock = NULL; + +static int washere = 0; + +static void * func(void * arg) +{ + assert(pthread_spin_trylock(&lock) == EBUSY); + + washere = 1; + + return 0; +} + +int pthread_test_spin2() +{ + pthread_t t; + + assert(pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE) == 0); + + assert(pthread_spin_lock(&lock) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + assert(pthread_join(t, NULL) == 0); + + assert(pthread_spin_unlock(&lock) == 0); + + assert(pthread_spin_destroy(&lock) == 0); + + assert(washere == 1); + + return 0; +} diff --git a/pthread/tests/spin3.c b/pthread/tests/spin3.c new file mode 100644 index 00000000..4acf1a06 --- /dev/null +++ b/pthread/tests/spin3.c @@ -0,0 +1,77 @@ +/* + * spin3.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Thread A locks spin - thread B tries to unlock. + * This should succeed, but it's undefined behaviour. + * + */ + +#include "test.h" + +static int wasHere = 0; + +static pthread_spinlock_t spin; + +static void * unlocker(void * arg) +{ + int expectedResult = (int) arg; + + wasHere++; + assert(pthread_spin_unlock(&spin) == expectedResult); + wasHere++; + return NULL; +} + +int pthread_test_spin3() +{ + pthread_t t; + + wasHere = 0; + assert(pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE) == 0); + assert(pthread_spin_lock(&spin) == 0); + assert(pthread_create(&t, NULL, unlocker, (void *) 0) == 0); + assert(pthread_join(t, NULL) == 0); + assert(pthread_spin_unlock(&spin) == EPERM); + assert(pthread_spin_destroy(&spin) == 0); + assert(wasHere == 2); + + return 0; +} diff --git a/pthread/tests/spin4.c b/pthread/tests/spin4.c new file mode 100644 index 00000000..70177228 --- /dev/null +++ b/pthread/tests/spin4.c @@ -0,0 +1,106 @@ +/* + * spin4.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Declare a static spinlock object, lock it, spin on it, + * and then unlock it again. + */ + +#include "test.h" + +static pthread_spinlock_t lock = PTHREAD_SPINLOCK_INITIALIZER; +static struct timeval currSysTimeStart; +static struct timeval currSysTimeStop; + +#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.tv_sec*1000+_TStop.tv_usec / 1000) \ + - (_TStart.tv_sec*1000+_TStart.tv_usec / 1000)) + +static int washere = 0; + +static void * func(void * arg) +{ + gettimeofday(&currSysTimeStart, NULL); + washere = 1; + assert(pthread_spin_lock(&lock) == 0); + assert(pthread_spin_unlock(&lock) == 0); + gettimeofday(&currSysTimeStop, NULL); + + return (void *) GetDurationMilliSecs(currSysTimeStart, currSysTimeStop); +} + +int pthread_test_spin4() +{ + long result = 0; + pthread_t t; + struct timeval sysTime; + + if (pthread_num_processors_np() == 1) + { + printf("spin test #4 not run - it requires multiple CPUs.\n"); + return 0; + } + + assert(pthread_spin_lock(&lock) == 0); + + assert(pthread_create(&t, NULL, func, NULL) == 0); + + while (washere == 0) + { + sched_yield(); + } + + do + { + sched_yield(); + gettimeofday(&sysTime, NULL); + } + while (GetDurationMilliSecs(currSysTimeStart, sysTime) <= 1000); + + assert(pthread_spin_unlock(&lock) == 0); + + assert(pthread_join(t, (void **) &result) == 0); + assert(result > 1000); + + assert(pthread_spin_destroy(&lock) == 0); + + assert(washere == 1); + + return 0; +} diff --git a/pthread/tests/stress1.c b/pthread/tests/stress1.c new file mode 100644 index 00000000..809d1c68 --- /dev/null +++ b/pthread/tests/stress1.c @@ -0,0 +1,288 @@ +/* + * stress1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Stress test condition variables, mutexes, semaphores. + * + * Test Method (Validation or Falsification): + * - Validation + * + * Requirements Tested: + * - Correct accounting of semaphore and condition variable waiters. + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * Attempting to expose race conditions in cond vars, semaphores etc. + * - Master attempts to signal slave close to when timeout is due. + * - Master and slave do battle continuously until main tells them to stop. + * - Afterwards, the CV must be successfully destroyed (will return an + * error if there are waiters (including any internal semaphore waiters, + * which, if there are, cannot not be real waiters). + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - CV is successfully destroyed. + * + * Fail Criteria: + * - CV destroy fails. + */ + +#include +#include "test.h" + +typedef long long int64_t; + +const unsigned int ITERATIONS = 1000; + +static pthread_t master, slave; +typedef struct + { + int value; + pthread_cond_t cv; + pthread_mutex_t mx; + } mysig_t; + +static int allExit; +static mysig_t control = {0, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; +static pthread_barrier_t startBarrier, readyBarrier, holdBarrier; +static int timeoutCount = 0; +static int signalsTakenCount = 0; +static int signalsSent = 0; +static int bias = 0; +static int timeout = 10; +// Must be > 0 + +enum +{ + CTL_STOP = -1 +}; + +/* + * Returns abstime 'milliseconds' from 'now'. + * + * Works for: -INT_MAX <= millisecs <= INT_MAX + */ +static struct timespec * + millisecondsFromNow (struct timespec * time, int millisecs) + { + struct timeval currSysTime; + int64_t nanosecs, secs; + const int64_t NANOSEC_PER_MILLISEC = 1000000; + const int64_t NANOSEC_PER_SEC = 1000000000; + + /* get current system time and add millisecs */ + gettimeofday(&currSysTime, NULL); + + secs = (int64_t)(currSysTime.tv_sec) + (millisecs / 1000); + nanosecs = ((int64_t) (millisecs%1000 + currSysTime.tv_usec / 1000)) * NANOSEC_PER_MILLISEC; + if (nanosecs >= NANOSEC_PER_SEC) + { + secs++; + nanosecs -= NANOSEC_PER_SEC; + } + else if (nanosecs < 0) + { + secs--; + nanosecs += NANOSEC_PER_SEC; + } + + time->tv_nsec = (long)nanosecs; + time->tv_sec = (long)secs; + + return time; + } + +static void * +masterThread (void * arg) +{ + int dither = (int) arg; + + timeout = (int) arg; + + pthread_barrier_wait(&startBarrier); + + do + { + int sleepTime; + + assert(pthread_mutex_lock(&control.mx) == 0); + control.value = timeout; + assert(pthread_mutex_unlock(&control.mx) == 0); + + /* + * We are attempting to send the signal close to when the slave + * is due to timeout. We feel around by adding some [non-random] dither. + * + * dither is in the range 2*timeout peak-to-peak + * sleep time is the average of timeout plus dither. + * e.g. + * if timeout = 10 then dither = 20 and + * sleep millisecs is: 5 <= ms <= 15 + * + * The bias value attempts to apply some negative feedback to keep + * the ratio of timeouts to signals taken close to 1:1. + * bias changes more slowly than dither so as to average more. + * + * Finally, if abs(bias) exceeds timeout then timeout is incremented. + */ + if (signalsSent % timeout == 0) + { + if (timeoutCount > signalsTakenCount) + { + bias++; + } + else if (timeoutCount < signalsTakenCount) + { + bias--; + } + if (bias < -timeout || bias > timeout) + { + timeout++; + } + } + dither = (dither + 1 ) % (timeout * 2); + sleepTime = (timeout - bias + dither) / 2; + phal_thread_sleep(sleepTime); + assert(pthread_cond_signal(&control.cv) == 0); + signalsSent++; + + pthread_barrier_wait(&holdBarrier); + pthread_barrier_wait(&readyBarrier); + } + while (!allExit); + + return NULL; +} + +static void * +slaveThread (void * arg) +{ + struct timespec time; + + pthread_barrier_wait(&startBarrier); + + do + { + assert(pthread_mutex_lock(&control.mx) == 0); + if (pthread_cond_timedwait(&control.cv, + &control.mx, + millisecondsFromNow(&time, control.value)) == ETIMEDOUT) + { + timeoutCount++; + } + else + { + signalsTakenCount++; + } + assert(pthread_mutex_unlock(&control.mx) == 0); + + pthread_barrier_wait(&holdBarrier); + pthread_barrier_wait(&readyBarrier); + } + while (!allExit); + + return NULL; +} + +int pthread_test_stress1() +{ + unsigned int i; + + control.value = 0; + control.cv = PTHREAD_COND_INITIALIZER; + control.mx = PTHREAD_MUTEX_INITIALIZER; + + timeoutCount = 0; + signalsTakenCount = 0; + signalsSent = 0; + bias = 0; + timeout = 10; + assert(pthread_barrier_init(&startBarrier, NULL, 3) == 0); + assert(pthread_barrier_init(&readyBarrier, NULL, 3) == 0); + assert(pthread_barrier_init(&holdBarrier, NULL, 3) == 0); + + assert(pthread_create(&master, NULL, masterThread, (void *) timeout) == 0); + assert(pthread_create(&slave, NULL, slaveThread, NULL) == 0); + + allExit = 0; + + pthread_barrier_wait(&startBarrier); + + for (i = 1; !allExit; i++) + { + pthread_barrier_wait(&holdBarrier); + if (i >= ITERATIONS) + { + allExit = 1; + } + pthread_barrier_wait(&readyBarrier); + } + + assert(pthread_join(slave, NULL) == 0); + assert(pthread_join(master, NULL) == 0); + + /* Cleanup */ + assert(pthread_barrier_destroy(&holdBarrier) == 0); + assert(pthread_barrier_destroy(&readyBarrier) == 0); + assert(pthread_barrier_destroy(&startBarrier) == 0); + assert(pthread_cond_destroy(&control.cv) == 0); + assert(pthread_mutex_destroy(&control.mx) == 0); + + /* Success. */ + return 0; +} diff --git a/pthread/tests/test.h b/pthread/tests/test.h new file mode 100644 index 00000000..1c1f6095 --- /dev/null +++ b/pthread/tests/test.h @@ -0,0 +1,294 @@ +/* + * test.h + * + * Useful definitions and declarations for tests. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#ifndef _PTHREAD_TEST_H_ +#define _PTHREAD_TEST_H_ + +#include +#include + +#include "phal.h" + +#include "pthread.h" +#include "sched.h" +#include +#include "semaphore.h" + +//#include + + +#define PTW32_THREAD_NULL_ID {NULL,0} + +#if defined(__MINGW32__) +#include +#elif defined(__BORLANDC__) +#define int64_t ULONGLONG +#else +#define int64_t _int64 +#endif + +extern const char * error_string; + + +/* + * The Mingw32 assert macro calls the CRTDLL _assert function + * which pops up a dialog. We want to run in batch mode so + * we define our own assert macro. + */ +#ifdef assert +# undef assert +#endif + +#ifndef ASSERT_TRACE +# define ASSERT_TRACE 0 +#else +# undef ASSERT_TRACE +# define ASSERT_TRACE 1 +#endif + +# define assert(e) \ + ((e) ? ((ASSERT_TRACE) ? fprintf(stdout, \ + "Assertion succeeded: (%s), file %s, line %d\n", \ + #e, __FILE__, (int) __LINE__), \ + fflush(stdout) : \ + 0) : \ + (fprintf(stderr, "Assertion failed: (" #e "), file " __FILE__ ", line %d\n", \ + (int) __LINE__), exit(1), 0)) + +extern int assertE; + +# define assert_eq(e, r) \ + (((assertE = (e)) == (r)) ? ((ASSERT_TRACE) ? fprintf(stdout, \ + "Assertion succeeded: (%s == %s), file %s, line %d\n", \ + #e, #r, __FILE__, (int) __LINE__), \ + fflush(stdout) : \ + 0) : \ + (fprintf(stderr, "Assertion failed: (%s (%d) == %s), file %s, line %d\n", \ + #e, assertE, #r, __FILE__, (int) __LINE__), exit(1), 0)) + +# define assert_e(e, o, r) \ + (((assertE = e) o (r)) ? ((ASSERT_TRACE) ? fprintf(stdout, \ + "Assertion succeeded: (%s), file %s, line %d\n", \ + #e, __FILE__, (int) __LINE__), \ + fflush(stdout) : \ + 0) : \ + (fprintf(stderr, "Assertion failed: (%s %s %s), file %s, line %d, error %s\n", \ + #e,#o,#r, __FILE__, (int) __LINE__, error_string[assertE]), exit(1), 0)) + +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +int pthread_test_mutex1(); +int pthread_test_mutex1e(); +int pthread_test_mutex1n(); +int pthread_test_mutex1r(); + +int pthread_test_mutex2(); +int pthread_test_mutex2e(); +int pthread_test_mutex2r(); + +int pthread_test_mutex3(); +int pthread_test_mutex3e(); +int pthread_test_mutex3r(); + +int pthread_test_mutex4(); + +int pthread_test_mutex5(); + +int pthread_test_mutex6(); +int pthread_test_mutex6e(); +int pthread_test_mutex6es(); +int pthread_test_mutex6n(); +int pthread_test_mutex6r(); +int pthread_test_mutex6rs(); +int pthread_test_mutex6s(); + +int pthread_test_mutex7(); +int pthread_test_mutex7e(); +int pthread_test_mutex7n(); +int pthread_test_mutex7r(); + +int pthread_test_mutex8(); +int pthread_test_mutex8e(); +int pthread_test_mutex8n(); +int pthread_test_mutex8r(); + +int pthread_test_valid1(); +int pthread_test_valid2(); + +int pthread_test_self1(); +int pthread_test_self2(); + +int pthread_test_equal1(); + +int pthread_test_create1(); +int pthread_test_create2(); +int pthread_test_create3(); + +int pthread_test_semaphore1(); +int pthread_test_semaphore2(); +int pthread_test_semaphore3(); +int pthread_test_semaphore4(); +int pthread_test_semaphore4t(); +int pthread_test_semaphore5(); +int pthread_test_semaphore6(); + +int pthread_test_barrier1(); +int pthread_test_barrier2(); +int pthread_test_barrier3(); +int pthread_test_barrier4(); +int pthread_test_barrier5(); + +int pthread_test_count1(); + +int pthread_test_create1(); +int pthread_test_create2(); +int pthread_test_create3(); + +int pthread_test_delay1(); +int pthread_test_delay2(); + +int pthread_test_errno1(); + +int pthread_test_join0(); +int pthread_test_join1(); +int pthread_test_join2(); +int pthread_test_join3(); +int pthread_test_join4(); + +int pthread_test_kill1(); + +int pthread_test_once1(); +int pthread_test_once2(); +int pthread_test_once3(); +int pthread_test_once4(); + +int pthread_test_spin1(); +int pthread_test_spin2(); +int pthread_test_spin3(); +int pthread_test_spin4(); + +int pthread_test_tsd1(); +int pthread_test_tsd2(); + +int pthread_test_condvar1_1(); +int pthread_test_condvar1_2(); +int pthread_test_condvar1(); +int pthread_test_condvar2_1(); +int pthread_test_condvar2(); +int pthread_test_condvar3(); +int pthread_test_condvar3_1(); +int pthread_test_condvar3_2(); +int pthread_test_condvar3_3(); +int pthread_test_condvar4(); +int pthread_test_condvar5(); +int pthread_test_condvar6(); +int pthread_test_condvar7(); +int pthread_test_condvar8(); +int pthread_test_condvar9(); + +int pthread_test_stress1(); + +int pthread_test_detach1(); + +int pthread_test_exit1(); +int pthread_test_exit2(); +int pthread_test_exit3(); +int pthread_test_exit4(); +int pthread_test_exit5(); + +int pthread_test_reuse1(); +int pthread_test_reuse2(); + +int pthread_test_rwlock1(); +int pthread_test_rwlock2(); +int pthread_test_rwlock2t(); +int pthread_test_rwlock3(); +int pthread_test_rwlock3t(); +int pthread_test_rwlock4(); +int pthread_test_rwlock4t(); +int pthread_test_rwlock5(); +int pthread_test_rwlock5t(); +int pthread_test_rwlock6(); +int pthread_test_rwlock6t(); +int pthread_test_rwlock6t2(); +int pthread_test_rwlock7(); +int pthread_test_rwlock8(); + +int pthread_test_priority1(); +int pthread_test_priority2(); + +int pthread_test_inherit1(); + +int pthread_test_cancel1(); +int pthread_test_cancel2(); +int pthread_test_cancel3(); +int pthread_test_cancel4(); +int pthread_test_cancel5(); +int pthread_test_cancel6a(); +int pthread_test_cancel6d(); +int pthread_test_cancel7(); +int pthread_test_cancel8(); +int pthread_test_cancel9(); + +int pthread_test_cleanup0(); +int pthread_test_cleanup1(); +int pthread_test_cleanup2(); +int pthread_test_cleanup3(); + +int pthread_test_bench1(); +int pthread_test_bench2(); +int pthread_test_bench3(); +int pthread_test_bench4(); + +int pthread_test_exception1(); +int pthread_test_exception2(); +int pthread_test_exception3(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/pthread/tests/test_main.c b/pthread/tests/test_main.c new file mode 100644 index 00000000..cffdc6e4 --- /dev/null +++ b/pthread/tests/test_main.c @@ -0,0 +1,505 @@ +#include "phal.h" +#include "test.h" + +const char * error_string; + +int assertE; + +///@todo: add cancellable wait for thread end for DSP/BIOS +///@todo: look at removing/changing ftime + +static void runBarrierTests(void) +{ + printf("Barrier test #1\n"); + pthread_test_barrier1(); + + printf("Barrier test #2\n"); + pthread_test_barrier2(); + + printf("Barrier test #3\n"); + pthread_test_barrier3(); + + printf("Barrier test #4\n"); + pthread_test_barrier4(); + + printf("Barrier test #5\n"); + pthread_test_barrier5(); +} + +static void runSemTests(void) +{ + + printf("Semaphore test #1\n"); + pthread_test_semaphore1(); + + printf("Semaphore test #2\n"); + pthread_test_semaphore2(); + + printf("Semaphore test #3\n"); + printf("Our semaphore's getvalue returns the number of pre-signaling values"); + printf("which is different from Linux returning the number of waiting threads.\n"); + //pthread_test_semaphore3(); + + printf("Semaphore test #4\n"); + printf("Ditto, and this tests cancel behavior, which we don't implement (yet).\n"); + //pthread_test_semaphore4(); + + printf("Semaphore test #4t\n"); + printf("Ditto\n"); + //pthread_test_semaphore4t(); + + printf("Semaphore test #5\n"); + pthread_test_semaphore5(); + + printf("Semaphore test #6\n"); + pthread_test_semaphore6(); + +} + +static void runThreadTests(void) +{ + + printf("Create test #1\n"); + pthread_test_create1(); + + printf("Create test #2\n"); + pthread_test_create2(); + + printf("Create test #3\n"); + pthread_test_create3(); + + printf("Join test #0\n"); + pthread_test_join0(); + + printf("Join test #1\n"); + pthread_test_join1(); + + printf("Join test #2\n"); + pthread_test_join2(); + + printf("Join test #3\n"); + pthread_test_join3(); + + printf("Join test #4\n"); + printf("Depends on cancel. Not running.\n"); + //pthread_test_join4(); + + printf("Kill test #1\n"); + printf("Depends on kill. Not running.\n"); + //pthread_test_kill1(); + + printf("Exit test #1\n"); + pthread_test_exit1(); + + printf("Exit test #2\n"); + pthread_test_exit2(); + + printf("Exit test #3\n"); + pthread_test_exit3(); + + printf("Exit test #4\n"); + printf("Cannot call pthread_exit() on a thread not created through pthread_create()\n"); + //pthread_test_exit4(); + + printf("Exit test #5\n"); + printf("Cannot call pthread_exit() on a thread not created through pthread_create()\n"); + //pthread_test_exit5(); + + /* These tests can not be run in series with other tests, + * as they rely on knowing what is on the reuse queue. + */ + /* + printf("Reuse test #1\n"); + pthread_test_reuse1(); + + printf("Reuse test #2\n"); + pthread_test_reuse2(); + */ + +// printf("Priority test #1\n"); +// pthread_test_priority1(); +// +// printf("Priority test #2\n"); +// pthread_test_priority2(); + +// printf("Inherit test #1\n"); +// pthread_test_inherit1(); ///@todo + +} + +static void runMiscTests(void) +{ + + printf("Valid test #1\n"); + pthread_test_valid1(); + + printf("Valid test #2\n"); + pthread_test_valid2(); + + printf("Self test #1\n"); + pthread_test_self1(); + + printf("Self test #2\n"); + pthread_test_self2(); + + printf("Equal test #1\n"); + pthread_test_equal1(); + + printf("Count test #1\n"); + pthread_test_count1(); + + //printf("Delay test #1\n"); + //pthread_test_delay1(); + + //printf("Delay test #2\n"); + //pthread_test_delay2(); + + //printf("Once test #1\n"); + //pthread_test_once1(); + + //printf("Once test #2\n"); + //pthread_test_once2(); + + //printf("Once test #3\n"); + //pthread_test_once3(); + + //printf("Once test #4\n"); + //pthread_test_once4(); + + //printf("TSD test #1\n"); + //pthread_test_tsd1(); + + //printf("TSD test #2\n"); + //pthread_test_tsd2(); + + //TODO: Yes. We use newlib's reent +#ifdef THREAD_SAFE_ERRNO + //printf("Errno test #1\n"); + //pthread_test_errno1(); +#endif // THREAD_SAFE_ERRNO + + //printf("Detach test #1\n"); + //pthread_test_detach1(); + +} + +static void runMutexTests(void) +{ + + printf("Mutex test #1\n"); + pthread_test_mutex1(); + + printf("Mutex test #1(e)\n"); + pthread_test_mutex1e(); + + printf("Mutex test #1(n)\n"); + pthread_test_mutex1n(); + + printf("Mutex test #1(r)\n"); + pthread_test_mutex1e(); + + printf("Mutex test #2\n"); + pthread_test_mutex2(); + + printf("Mutex test #2(e)\n"); + pthread_test_mutex2e(); + + printf("Mutex test #2(r)\n"); + pthread_test_mutex2r(); + + printf("Mutex test #3\n"); + pthread_test_mutex3(); + + printf("Mutex test #3(e)\n"); + pthread_test_mutex3e(); + + printf("Mutex test #3(r)\n"); + pthread_test_mutex3r(); + + printf("Mutex test #4\n"); + printf("Depends on undefined behavior. OpenBSD's undef is to abort, causing test to fail.\n"); + //pthread_test_mutex4(); + + printf("Mutex test #5\n"); + pthread_test_mutex5(); + + printf("Mutex test #6\n"); + printf("Depends on undefined behavior (unlocking from another thread). OpenBSD's undef is to abort, causing test to fail.\n"); + //pthread_test_mutex6(); + + printf("Mutex test #6e\n"); + pthread_test_mutex6e(); + + printf("Mutex test #6es\n"); + pthread_test_mutex6es(); + + printf("Mutex test #6n\n"); + printf("Depends on undefined behavior (unlocking from another thread). OpenBSD's undef is to abort, causing test to fail.\n"); + //pthread_test_mutex6n(); + + printf("Mutex test #6r\n"); + pthread_test_mutex6r(); + + printf("Mutex test #6rs\n"); + pthread_test_mutex6rs(); + + printf("Mutex test #6s\n"); + printf("Depends on undefined behavior (unlocking from another thread). OpenBSD's undef is to abort, causing test to fail.\n"); + //pthread_test_mutex6s(); + + printf("Mutex test #7\n"); + printf("Depends on undefined behavior (unlocking an unlocked mutex). OpenBSD's undef is to abort, causing test to fail.\n"); + //pthread_test_mutex7(); + + printf("Mutex test #7e\n"); + pthread_test_mutex7e(); + + printf("Mutex test #7n\n"); + pthread_test_mutex7n(); + + printf("Mutex test #7r\n"); + pthread_test_mutex7r(); + + //printf("Mutex test #8\n"); + //pthread_test_mutex8(); + + //printf("Mutex test #8e\n"); + //pthread_test_mutex8e(); + + //printf("Mutex test #8n\n"); + //pthread_test_mutex8n(); + + //printf("Mutex test #8r\n"); + //pthread_test_mutex8r(); + +} + +static void runSpinTests() +{ + printf("Spin test #1\n"); + pthread_test_spin1(); + + printf("Spin test #2\n"); + pthread_test_spin2(); + + printf("Spin test #3\n"); + pthread_test_spin3(); + + //printf("Spin test #4\n"); + //pthread_test_spin4(); + +} + +static void runCondvarTests() +{ + + printf("Condvar test #1\n"); + pthread_test_condvar1(); + + /*printf("Condvar test #1-1\n"); + pthread_test_condvar1_1(); + + printf("Condvar test #1-2\n"); + pthread_test_condvar1_2();*/ + + printf("Condvar test #2\n"); + pthread_test_condvar2(); + + printf("Condvar test #2-1\n"); + pthread_test_condvar2_1(); + + printf("Condvar test #3\n"); + pthread_test_condvar3(); + + printf("Condvar test #3-1\n"); + pthread_test_condvar3_1(); + + printf("Condvar test #3-2\n"); + pthread_test_condvar3_2(); + + printf("Condvar test #3-3\n"); + pthread_test_condvar3_3(); + + printf("Condvar test #4\n"); + pthread_test_condvar4(); + + printf("Condvar test #5\n"); + pthread_test_condvar5(); + + printf("Condvar test #6\n"); + printf("Test is unsound. It relies on timing. Needs to be rewritten.\n"); + // TODO: Rewrite this to be sound + //pthread_test_condvar6(); + + printf("Condvar test #7\n"); + printf("Test relies on cancel, which we don't yet implement\n."); + //pthread_test_condvar7(); + + printf("Condvar test #8\n"); + pthread_test_condvar8(); + + printf("Condvar test #9\n"); + pthread_test_condvar9(); + +} + +static void runStressTests() +{ + //printf("Stress test #1\n"); + //pthread_test_stress1(); +} + +static void runRwlockTests() +{ + printf("Rwlock test #1\n"); + pthread_test_rwlock1(); + + printf("Rwlock test #2\n"); + pthread_test_rwlock2(); + + printf("Rwlock test #2t\n"); + pthread_test_rwlock2t(); + + printf("Rwlock test #3\n"); + pthread_test_rwlock3(); + + printf("Rwlock test #3t\n"); + pthread_test_rwlock3t(); + + printf("Rwlock test #4\n"); + pthread_test_rwlock4(); + + printf("Rwlock test #4t\n"); + pthread_test_rwlock4t(); + + printf("Rwlock test #5\n"); + pthread_test_rwlock5(); + + printf("Rwlock test #5t\n"); + pthread_test_rwlock5t(); + + printf("Rwlock test #6\n"); + pthread_test_rwlock6(); + + printf("Rwlock test #6t\n"); + pthread_test_rwlock6t(); + + printf("Rwlock test #6t2\n"); + pthread_test_rwlock6t2(); + + printf("Rwlock test #7\n"); + pthread_test_rwlock7(); + + printf("Rwlock test #8\n"); + pthread_test_rwlock8(); + +} + +static void runCancelTests() +{ + + printf("Cancel test #1\n"); + pthread_test_cancel1(); + + printf("Cancel test #2\n"); + pthread_test_cancel2(); + + printf("Cancel test #3\n"); + pthread_test_cancel3(); + + printf("Cancel test #4\n"); + pthread_test_cancel4(); + + printf("Cancel test #5\n"); + pthread_test_cancel5(); + + printf("Cancel test #6a\n"); + pthread_test_cancel6a(); + + printf("Cancel test #6d\n"); + pthread_test_cancel6d(); + + /* Cleanup only occurs for async cancellation. + * If we don't support this, can't test it... + */ + printf("Cleanup test #0\n"); + pthread_test_cleanup0(); + + printf("Cleanup test #1\n"); + pthread_test_cleanup1(); + + printf("Cleanup test #2\n"); + pthread_test_cleanup2(); + + printf("Cleanup test #3\n"); + pthread_test_cleanup3(); +} + +static void runBenchTests() +{ + + //printf("Benchmark test #1\n"); + //pthread_test_bench1(); + + //printf("Benchmark test #2\n"); + //pthread_test_bench2(); + + //printf("Benchmark test #3\n"); + //pthread_test_bench3(); + + //printf("Benchmark test #4\n"); + //pthread_test_bench4(); +} + +static void runExceptionTests() +{ + //printf("Exception test #1\n"); + //pthread_test_exception1(); + +/*// This test intentially crashes the app + // (unhandled exception) + //printf("Exception test #2\n"); + //pthread_test_exception2(); +*/// + + //printf("Exception test #3\n"); + //pthread_test_exception3(); +} + +void pte_test_main() +{ + int i; + + // Dynamically initialize. + /*if (!pthread_init()) + { + printf("Failed to initialize pthreads library.\n"); + return; + }*/ + + printf("Running tests...\n"); + for (i=0;i<2;i++) + { + printf("=========================\n"); + printf(" Test iteration #%d\n\n",i); + printf("=========================\n"); + + runThreadTests(); + runMiscTests(); + runMutexTests(); + runSemTests(); + runCondvarTests(); + runBarrierTests(); + runSpinTests(); + runRwlockTests(); + //runCancelTests(); + //runExceptionTests(); + //runBenchTests(); + //runStressTests(); + + } + + printf("Tests complete!\n"); + +} + diff --git a/pthread/tests/tsd1.c b/pthread/tests/tsd1.c new file mode 100644 index 00000000..4ba8acc5 --- /dev/null +++ b/pthread/tests/tsd1.c @@ -0,0 +1,227 @@ +/* + * tsd1.c + * + * Test Thread Specific Data (TSD) key creation and destruction. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * -------------------------------------------------------------------------- + * + * Description: + * - + * + * Test Method (validation or falsification): + * - validation + * + * Requirements Tested: + * - keys are created for each existing thread including the main thread + * - keys are created for newly created threads + * - keys are thread specific + * - destroy routine is called on each thread exit including the main thread + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Environment: + * - + * + * Input: + * - none + * + * Output: + * - text to stdout + * + * Assumptions: + * - already validated: pthread_create() + * pthread_once() + * - main thread also has a POSIX thread identity + * + * Pass Criteria: + * - stdout matches file reference/tsd1.out + * + * Fail Criteria: + * - fails to match file reference/tsd1.out + * - output identifies failed component + */ + +#include "test.h" +//#include "implement.h" +#include + + +enum +{ + NUM_THREADS = 16//OS_MAX_SIMUL_THREADS +}; + +static pthread_key_t key = NULL; +static int accesscount[NUM_THREADS]; +static int thread_set[NUM_THREADS]; +static int thread_destroyed[NUM_THREADS]; +static pthread_barrier_t startBarrier; + +static void +destroy_key(void * arg) +{ + int * j = (int *) arg; + + (*j)++; + + assert(*j == 2); + + thread_destroyed[j - accesscount] = 1; +} + +static void +setkey(void * arg) +{ + int * j = (int *) arg; + + thread_set[j - accesscount] = 1; + + assert(*j == 0); + + assert(pthread_setspecific(key, arg) == 0); + assert(pthread_setspecific(key, arg) == 0); + assert(pthread_setspecific(key, arg) == 0); + + assert(pthread_getspecific(key) == arg); + + (*j)++; + + assert(*j == 1); +} + +static void * +mythread(void * arg) +{ + (void) pthread_barrier_wait(&startBarrier); + + // Note that this test must go here, rather than + // in setkey() above, as setkey() is called by the main + // (non-pthread) thread, which has already been running + // and thus may have a non-zero value for the TLS for + // this key. + assert(pthread_getspecific(key) == NULL); + + setkey(arg); + + return 0; + + /* Exiting the thread will call the key destructor. */ +} + +int pthread_test_tsd1() +{ + int i; + int fail = 0; + pthread_t thread[NUM_THREADS]; + + /* Just to avoid compiler warnings */ + thread_set[0] = thread_set[0]; + thread_destroyed[0] = thread_destroyed[0]; + + assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0); + + for (i = 1; i < NUM_THREADS/2; i++) + { + accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; + assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); + } + + /* + * Here we test that existing threads will get a key created + * for them. + */ + assert(pthread_key_create(&key, destroy_key) == 0); + + (void) pthread_barrier_wait(&startBarrier); + + /* + * Test main thread key. + */ + accesscount[0] = 0; + setkey((void *) &accesscount[0]); + + /* + * Here we test that new threads will get a key created + * for them. + */ + for (i = NUM_THREADS/2; i < NUM_THREADS; i++) + { + accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; + + assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); + } + + /* + * Wait for all threads to complete. + */ + for (i = 1; i < NUM_THREADS; i++) + { + int result = 0; + + assert(pthread_join(thread[i], (void **) &result) == 0); + } + +// assert(pthread_key_delete(key) == 0); + + assert(pthread_barrier_destroy(&startBarrier) == 0); + + for (i = 1; i < NUM_THREADS; i++) + { + /* + * The counter is incremented once when the key is set to + * a value, and again when the key is destroyed. If the key + * doesn't get set for some reason then it will still be + * NULL and the destroy function will not be called, and + * hence accesscount will not equal 2. + */ + if (accesscount[i] != 2) + { + fail++; + } + } + + assert(fail == 0); + + return (fail); +} diff --git a/pthread/tests/tsd2.c b/pthread/tests/tsd2.c new file mode 100644 index 00000000..362495f5 --- /dev/null +++ b/pthread/tests/tsd2.c @@ -0,0 +1,225 @@ +/* + * tsd2.c + * + * Test Thread Specific Data (TSD) key creation and destruction. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * -------------------------------------------------------------------------- + * + * Description: + * - + * + * Test Method (validation or falsification): + * - validation + * + * Requirements Tested: + * - keys are created for each existing thread including the main thread + * - keys are created for newly created threads + * - keys are thread specific + * - destroy routine is called on each thread exit including the main thread + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Environment: + * - + * + * Input: + * - none + * + * Output: + * - text to stdout + * + * Assumptions: + * - already validated: pthread_create() + * pthread_once() + * - main thread also has a POSIX thread identity + * + * Pass Criteria: + * - stdout matches file reference/tsd1.out + * + * Fail Criteria: + * - fails to match file reference/tsd1.out + * - output identifies failed component + */ + +#include "test.h" +//#include "implement.h" +#include + + +enum +{ + NUM_THREADS = 20 +}; + +static pthread_key_t key = NULL; +static int accesscount[NUM_THREADS]; +static int thread_set[NUM_THREADS]; +static int thread_destroyed[NUM_THREADS]; +static pthread_barrier_t startBarrier; + +static void +destroy_key(void * arg) +{ + int * j = (int *) arg; + + (*j)++; + + /* Set TSD key from the destructor to test destructor iteration */ + if (*j == 2) + assert(pthread_setspecific(key, arg) == 0); + else + assert(*j == 3); + + thread_destroyed[j - accesscount] = 1; +} + +static void +setkey(void * arg) +{ + int * j = (int *) arg; + + thread_set[j - accesscount] = 1; + + assert(*j == 0); + + assert(pthread_getspecific(key) == NULL); + + assert(pthread_setspecific(key, arg) == 0); + assert(pthread_setspecific(key, arg) == 0); + assert(pthread_setspecific(key, arg) == 0); + + assert(pthread_getspecific(key) == arg); + + (*j)++; + + assert(*j == 1); +} + +static void * +mythread(void * arg) +{ + (void) pthread_barrier_wait(&startBarrier); + + setkey(arg); + + return 0; + + /* Exiting the thread will call the key destructor. */ +} + +int pthread_test_tsd2() +{ + int i; + int fail = 0; + pthread_t thread[NUM_THREADS]; + + /* Just to avoid compiler warnings */ + thread_set[0] = thread_set[0]; + thread_destroyed[0] = thread_destroyed[0]; + + assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0); + + for (i = 1; i < NUM_THREADS/2; i++) + { + accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; + assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); + } + + /* + * Here we test that existing threads will get a key created + * for them. + */ + assert(pthread_key_create(&key, destroy_key) == 0); + + (void) pthread_barrier_wait(&startBarrier); + + /* + * Test main thread key. + */ + accesscount[0] = 0; + setkey((void *) &accesscount[0]); + + /* + * Here we test that new threads will get a key created + * for them. + */ + for (i = NUM_THREADS/2; i < NUM_THREADS; i++) + { + accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; + assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); + } + + /* + * Wait for all threads to complete. + */ + for (i = 1; i < NUM_THREADS; i++) + { + int result = 0; + + assert(pthread_join(thread[i], (void **) &result) == 0); + } + + assert(pthread_key_delete(key) == 0); + + assert(pthread_barrier_destroy(&startBarrier) == 0); + + for (i = 1; i < NUM_THREADS; i++) + { + /* + * The counter is incremented once when the key is set to + * a value, and again when the key is destroyed. If the key + * doesn't get set for some reason then it will still be + * NULL and the destroy function will not be called, and + * hence accesscount will not equal 2. + */ + if (accesscount[i] != 3) + { + fail++; + } + } + + fflush(stderr); + + return (fail); +} diff --git a/pthread/tests/valid1.c b/pthread/tests/valid1.c new file mode 100644 index 00000000..07eef3ed --- /dev/null +++ b/pthread/tests/valid1.c @@ -0,0 +1,111 @@ +/* + * File: valid1.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Test that thread validation works. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +enum +{ + NUMTHREADS = 1 +}; + +static int washere = 0; + +static void * func(void * arg) +{ + washere = 1; + return (void *) 0; +} + +int pthread_test_valid1(void) +{ + pthread_t t; + void * result = NULL; + + washere = 0; + assert(pthread_create(&t, NULL, func, NULL) == 0); + assert(pthread_join(t, &result) == 0); + assert(result == 0); + assert(washere == 1); + // TODO: Implement sched_yield + phal_thread_sleep(0); + // TODO: Implement a way to check if a thread is dead + //assert(pthread_kill(t, 0) == ESRCH); + + return 0; +} diff --git a/pthread/tests/valid2.c b/pthread/tests/valid2.c new file mode 100644 index 00000000..dce8f367 --- /dev/null +++ b/pthread/tests/valid2.c @@ -0,0 +1,89 @@ +/* + * File: valid2.c + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems + * Copyright(C) 2008 Jason Schmidlapp + * + * Contact Email: jschmidlapp@users.sourceforge.net + * + * + * Based upon Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The original list of contributors to the Pthreads-win32 project + * is contained in the file CONTRIBUTORS.ptw32 included with the + * source code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * -------------------------------------------------------------------------- + * + * Test Synopsis: + * - Confirm that thread validation fails for garbage thread ID. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#include "test.h" + +int pthread_test_valid2(void) +{ + pthread_t NullThread = PTW32_THREAD_NULL_ID; + + //assert(pthread_kill(NullThread, 0) == ESRCH); + + return 0; +} diff --git a/pthread/thread_private.h b/pthread/thread_private.h new file mode 100644 index 00000000..e88e4e83 --- /dev/null +++ b/pthread/thread_private.h @@ -0,0 +1,419 @@ +/* $OpenBSD: thread_private.h,v 1.32 2017/11/04 22:53:57 jca Exp $ */ + +/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman */ + +#ifndef _THREAD_PRIVATE_H_ +#define _THREAD_PRIVATE_H_ + +#include /* for FILE and __isthreaded */ +#if 0 +#define _MALLOC_MUTEXES 4 +void _malloc_init(int); +#ifdef __LIBC__ +PROTO_NORMAL(_malloc_init); +#endif /* __LIBC__ */ +#endif + +/* + * The callbacks needed by libc to handle the threaded case. + * NOTE: Bump the version when you change the struct contents! + * + * tc_canceled: + * If not NULL, what to do when canceled (otherwise _exit(0)) + * + * tc_flockfile, tc_ftrylockfile, and tc_funlockfile: + * If not NULL, these implement the flockfile() family. + * XXX In theory, you should be able to lock a FILE before + * XXX loading libpthread and have that be a real lock on it, + * XXX but that doesn't work without the libc base version + * XXX tracking the recursion count. + * + * tc_malloc_lock and tc_malloc_unlock: + * tc_atexit_lock and tc_atexit_unlock: + * tc_atfork_lock and tc_atfork_unlock: + * tc_arc4_lock and tc_arc4_unlock: + * The locks used by the malloc, atexit, atfork, and arc4 subsystems. + * These have to be ordered specially in the fork/vfork wrappers + * and may be implemented differently than the general mutexes + * in the callbacks below. + * + * tc_mutex_lock and tc_mutex_unlock: + * Lock and unlock the given mutex. If the given mutex is NULL + * a mutex is allocated and initialized automatically. + * + * tc_mutex_destroy: + * Destroy/deallocate the given mutex. + * + * tc_tag_lock and tc_tag_unlock: + * Lock and unlock the mutex associated with the given tag. + * If the given tag is NULL a tag is allocated and initialized + * automatically. + * + * tc_tag_storage: + * Returns a pointer to per-thread instance of data associated + * with the given tag. If the given tag is NULL a tag is + * allocated and initialized automatically. + * + * tc_fork, tc_vfork: + * If not NULL, they are called instead of the syscall stub, so that + * the thread library can do necessary locking and reinitialization. + * + * tc_thread_release: + * Handles the release of a thread's TIB and struct pthread and the + * notification of other threads...when there are other threads. + * + * tc_thread_key_zero: + * For each thread, zero out the key data associated with the given key. + + * If doesn't define TCB_GET(), then locating the TCB in a + * threaded process requires a syscall (__get_tcb(2)) which is too much + * overhead for single-threaded processes. For those archs, there are two + * additional callbacks, though they are placed first in the struct for + * convenience in ASM: + * + * tc_errnoptr: + * Returns the address of the thread's errno. + * + * tc_tcb: + * Returns the address of the thread's TCB. + */ + +#include "phal.h" + +struct pthread; +struct thread_callbacks { + int *(*tc_errnoptr)(void); /* MUST BE FIRST */ + void *(*tc_tcb)(void); + /*__dead */void (*tc_canceled)(void); + void (*tc_flockfile)(FILE *); + int (*tc_ftrylockfile)(FILE *); + void (*tc_funlockfile)(FILE *); + void (*tc_malloc_lock)(int); + void (*tc_malloc_unlock)(int); + void (*tc_atexit_lock)(void); + void (*tc_atexit_unlock)(void); + void (*tc_atfork_lock)(void); + void (*tc_atfork_unlock)(void); + void (*tc_arc4_lock)(void); + void (*tc_arc4_unlock)(void); + void (*tc_mutex_lock)(void **); + void (*tc_mutex_unlock)(void **); + void (*tc_mutex_destroy)(void **); + void (*tc_tag_lock)(void **); + void (*tc_tag_unlock)(void **); + void *(*tc_tag_storage)(void **, void *, size_t, void *); + __pid_t (*tc_fork)(void); + __pid_t (*tc_vfork)(void); + void (*tc_thread_release)(struct pthread *); + void (*tc_thread_key_zero)(int); +}; + +//__BEGIN_PUBLIC_DECLS +/* + * Set the callbacks used by libc + */ +void _thread_set_callbacks(const struct thread_callbacks *_cb, size_t _len); +//__END_PUBLIC_DECLS + +#ifdef __LIBC__ +__BEGIN_HIDDEN_DECLS +/* the current set */ +extern struct thread_callbacks _thread_cb; +__END_HIDDEN_DECLS +#endif /* __LIBC__ */ + +/* + * helper macro to make unique names in the thread namespace + */ +#define __THREAD_NAME(name) __CONCAT(_thread_tagname_,name) + +/* + * Macros used in libc to access thread mutex, keys, and per thread storage. + * _THREAD_PRIVATE_KEY and _THREAD_PRIVATE_MUTEX are different macros for + * historical reasons. They do the same thing, define a static variable + * keyed by 'name' that identifies a mutex and a key to identify per thread + * data. + */ +#define _THREAD_PRIVATE_KEY(name) \ + static void *__THREAD_NAME(name) +#define _THREAD_PRIVATE_MUTEX(name) \ + static void *__THREAD_NAME(name) + + +#ifndef __LIBC__ /* building some sort of reach around */ + +#define _THREAD_PRIVATE_MUTEX_LOCK(name) do {} while (0) +#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) do {} while (0) +#define _THREAD_PRIVATE(keyname, storage, error) &(storage) +#define _MUTEX_LOCK(mutex) do {} while (0) +#define _MUTEX_UNLOCK(mutex) do {} while (0) +#define _MUTEX_DESTROY(mutex) do {} while (0) +#define _MALLOC_LOCK(n) do {} while (0) +#define _MALLOC_UNLOCK(n) do {} while (0) +#define _ATEXIT_LOCK() do {} while (0) +#define _ATEXIT_UNLOCK() do {} while (0) +#define _ATFORK_LOCK() do {} while (0) +#define _ATFORK_UNLOCK() do {} while (0) +#define _ARC4_LOCK() do {} while (0) +#define _ARC4_UNLOCK() do {} while (0) + +#else /* building libc */ +#define _THREAD_PRIVATE_MUTEX_LOCK(name) \ + do { \ + if (_thread_cb.tc_tag_lock != NULL) \ + _thread_cb.tc_tag_lock(&(__THREAD_NAME(name))); \ + } while (0) +#define _THREAD_PRIVATE_MUTEX_UNLOCK(name) \ + do { \ + if (_thread_cb.tc_tag_unlock != NULL) \ + _thread_cb.tc_tag_unlock(&(__THREAD_NAME(name))); \ + } while (0) +#define _THREAD_PRIVATE(keyname, storage, error) \ + (_thread_cb.tc_tag_storage == NULL ? &(storage) : \ + _thread_cb.tc_tag_storage(&(__THREAD_NAME(keyname)), \ + &(storage), sizeof(storage), error)) + +#if 0 +/* + * Macros used in libc to access mutexes. + */ +#define _MUTEX_LOCK(mutex) \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_mutex_lock(mutex); \ + } while (0) +#define _MUTEX_UNLOCK(mutex) \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_mutex_unlock(mutex); \ + } while (0) +#define _MUTEX_DESTROY(mutex) \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_mutex_destroy(mutex); \ + } while (0) + +/* + * malloc lock/unlock prototypes and definitions + */ +#define _MALLOC_LOCK(n) \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_malloc_lock(n); \ + } while (0) +#define _MALLOC_UNLOCK(n) \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_malloc_unlock(n); \ + } while (0) + +#define _ATEXIT_LOCK() \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_atexit_lock(); \ + } while (0) +#define _ATEXIT_UNLOCK() \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_atexit_unlock(); \ + } while (0) + +#define _ATFORK_LOCK() \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_atfork_lock(); \ + } while (0) +#define _ATFORK_UNLOCK() \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_atfork_unlock(); \ + } while (0) + +#define _ARC4_LOCK() \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_arc4_lock(); \ + } while (0) +#define _ARC4_UNLOCK() \ + do { \ + if (__isthreaded) \ + _thread_cb.tc_arc4_unlock(); \ + } while (0) +#endif +#endif /* __LIBC__ */ + + +/* + * Copyright (c) 2004,2005 Ted Unangst + * 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. + * + * Do not reorder _atomic_lock_t and sem_t variables in the structs. + * This is due to alignment requirements of certain arches like hppa. + * The current requirement is 16 bytes. + * + * THE MACHINE DEPENDENT CERROR CODE HAS HARD CODED OFFSETS INTO PTHREAD_T! + */ + +#include +#include +#include +#include +// TODO: Put this in newlwib +#include "semaphore.h" +#include "spinlock.h" + +#define _SPINLOCK_UNLOCKED _ATOMIC_LOCK_UNLOCKED + +struct __sem { + volatile int waitcount; + volatile int value; + phal_semaphore sem; + int shared; +}; + +TAILQ_HEAD(pthread_queue, pthread); + +struct pthread_mutex { + phal_semaphore sem; + _Atomic(int) lock; + int type; + pthread_t owner; + int count; + int prioceiling; +}; + +struct pthread_cond { + phal_semaphore sem; + clockid_t clock; + struct pthread_mutex *mutex; +}; + +struct pthread_mutex_attr { + int ma_type; + int ma_protocol; + int ma_prioceiling; +}; + +struct pthread_cond_attr { + clockid_t ca_clock; +}; + +struct pthread_attr { + void *stack_addr; + size_t stack_size; + size_t guard_size; + int detach_state; + int contention_scope; + int sched_policy; + struct sched_param sched_param; + int sched_inherit; +}; + +struct rthread_storage { + int keyid; + struct rthread_storage *next; + void *data; +}; + +struct rthread_cleanup_fn { + void (*fn)(void *); + void *arg; + struct rthread_cleanup_fn *next; +}; + +struct stack; + +// Some bits from TIB +/* + * tib_cantcancel values is non-zero if the thread should skip all + * cancellation processing + */ +#define CANCEL_DISABLED 1 +#define CANCEL_DYING 2 + +/* + * tib_cancel_point is non-zero if we're in a cancel point; its modified + * by the cancel point code and read by the cancellation signal handler + */ +#define CANCEL_POINT 1 +#define CANCEL_POINT_DELAYED 2 + +struct pthread { + struct __sem donesem; + unsigned int flags; + _atomic_lock_t flags_lock; + void *retval; + void *(*fn)(void *); + void *arg; + char name[32]; + struct stack *stack; + LIST_ENTRY(pthread) threads; + TAILQ_ENTRY(pthread) waiting; + pthread_cond_t blocking_cond; + struct pthread_attr attr; + struct rthread_storage *local_storage; + struct rthread_cleanup_fn *cleanup_fns; + + // Bring tib inside thread + int tib_cantcancel; + int tib_cancel_point; + int tib_canceled; + int tib_errno; + int tib_thread_flags; /* internal to libpthread */ + + // HAL + phal_tid tib_tid; + + /* cancel received in a delayed cancel block? */ + int delayed_cancel; +}; +/* flags in pthread->flags */ +#define THREAD_DONE 0x001 +#define THREAD_DETACHED 0x002 + +/* flags in tib->tib_thread_flags */ +#define TIB_THREAD_ASYNC_CANCEL 0x001 +#define TIB_THREAD_INITIAL_STACK 0x002 /* has stack from exec */ + +#define ENTER_DELAYED_CANCEL_POINT(tib, self) \ + (self)->delayed_cancel = 0; \ + ENTER_CANCEL_POINT_INNER(tib, 1, 1) + +/* + * Internal functions exported from libc's thread bits for use by libpthread + */ +void _spinlock(volatile _atomic_lock_t *); +int _spinlocktry(volatile _atomic_lock_t *); +void _spinunlock(volatile _atomic_lock_t *); + +void _rthread_debug(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +pid_t _thread_dofork(pid_t (*_sys_fork)(void)); + +/* + * Threading syscalls not declared in system headers + */ +/*__dead void __threxit(pid_t *); +int __thrsleep(const volatile void *, clockid_t, + const struct timespec *, volatile void *, const int *); +int __thrwakeup(const volatile void *, int n); +int __thrsigdivert(sigset_t, siginfo_t *, const struct timespec *);*/ + +#endif /* _THREAD_PRIVATE_H_ */ diff --git a/pthread/tib_old.h b/pthread/tib_old.h new file mode 100644 index 00000000..db45cf3b --- /dev/null +++ b/pthread/tib_old.h @@ -0,0 +1,253 @@ +/* $OpenBSD: tib.h,v 1.6 2017/11/28 18:57:02 kettenis Exp $ */ +/* + * Copyright (c) 2011,2014 Philip Guenther + * + * 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 Information Block (TIB) and Thread Local Storage (TLS) handling + * (the TCB, Thread Control Block, is part of the TIB) + */ + +#ifndef _TIB_H_ +#define _TIB_H_ + +#include +// #include +// Ripped from the above header + +/* ELF TLS ABI calls for small TCB, with static TLS data after it */ +#define TLS_VARIANT 1 + +/*static inline void * +__aarch64_read_tcb(void) +{ + void *tcb; + __asm volatile("mrs %x0, tpidr_el0": "=r" (tcb)); + return tcb; +} + +#define TCB_GET() __aarch64_read_tcb() +*/ + +void *phal_get_tls(void); +#define TCB_GET() phal_get_tls() + +#include +#include + +/* + * This header defines struct tib and at least eight macros: + * TLS_VARIANT + * Either 1 or 2 (Actually defined by ) + * + * TCB_SET(tcb) + * Set the TCB pointer for this thread to 'tcb' + * + * TCB_GET() + * Return the TCB pointer for this thread + * + * TCB_TO_TIB(tcb) + * Given a TCB pointer, return the matching TIB pointer + * + * TIB_TO_TCB(tib) + * Given a TIB pointer, return the matching TCB pointer + * + * TIB_INIT(tib, dtv, thread) + * Initializes a TIB for a new thread, using the supplied + * values for its dtv and thread pointers + * + * TIB_GET() + * Short-hand for TCB_TO_TIB(TCB_GET()) + * + * TIB_EXTRA_ALIGN + * On TLS varaint 2 archs, what alignment is sufficient + * for the extra space that will be used for struct pthread? + * + * The following functions are provided by either ld.so (dynamic) or + * libc (static) for allocating and freeing a common memory block that + * will hold both the TIB and the pthread structure: + * _dl_allocate_tib(sizeof(struct pthread)) + * Allocates a combined TIB and pthread memory region. + * The argument is the amount of space to reserve + * for the pthread structure. Returns a pointer to + * the TIB inside the allocated block. + * + * _dl_free_tib(tib, sizeof(struct pthread)) + * Frees a TIB and pthread block previously allocated + * with _dl_allocate_tib(). Must be passed the return + * value of that previous call. + */ + +/* + * Regarding : + * - it must define the TLS_VARIANT macro + * - it may define TCB_OFFSET if the TCB address in the kernel and/or + * register is offset from the actual TCB address. TCB_OFFSET > 0 + * means the kernel/register points to *after* the real data. + * - if there's a faster way to get or set the TCB pointer for the thread + * than the __{get,set}_tcb() syscalls, it should define either or both + * the TCB_{GET,SET} macros to do so. + */ + + +/* All archs but mips64 have fast TCB_GET() and don't need caching */ +#ifndef __mips64__ +# define TCB_HAVE_MD_GET 1 +#endif +#ifdef TCB_SET +# define TCB_HAVE_MD_SET 1 +#else +# define TCB_SET(tcb) __set_tcb(tcb) +#endif +#ifndef TCB_OFFSET +# define TCB_OFFSET 0 +#endif + +/* + * tib_cantcancel values is non-zero if the thread should skip all + * cancellation processing + */ +#define CANCEL_DISABLED 1 +#define CANCEL_DYING 2 + +/* + * tib_cancel_point is non-zero if we're in a cancel point; its modified + * by the cancel point code and read by the cancellation signal handler + */ +#define CANCEL_POINT 1 +#define CANCEL_POINT_DELAYED 2 + + +//#if TLS_VARIANT == 1 +/* + * ABI specifies that the static TLS data starts two words after the + * (notional) thread pointer, with the first of those two words being + * the TLS dtv pointer. The other (second) word is reserved for the + * implementation, so we place the pointer to the thread structure there, + * but we place our actual thread bits before the TCB, at negative offsets + * from the TCB pointer. Ergo, memory is laid out, low to high, as: + * + * [pthread structure] + * TIB { + * ...cancelation and other int-sized info... + * int errno + * void *locale + * TCB (- TCB_OFFSET) { + * void *dtv + * struct pthread *thread + * } + * } + * static TLS data + */ + +struct tib { + void *tib_atexit; + int tib_thread_flags; /* internal to libpthread */ + phal_tid tib_tid; + //pid_t tib_tid; + int tib_cantcancel; + int tib_cancel_point; + int tib_canceled; + int tib_errno; + void *tib_locale; + void *tib_dtv; /* internal to the runtime linker */ + void *tib_thread; +}; + + +//#elif TLS_VARIANT == 2 +/* + * ABI specifies that the static TLS data occupies the memory before + * the TCB pointer, at negative offsets, and that on i386 and amd64 + * the word the TCB points to contains a pointer to itself. So, + * we place errno and our thread bits after that. Memory is laid + * out, low to high, as: + * static TLS data + * TIB { + * TCB (- TCB_OFFSET) { + * self pointer [i386/amd64 only] + * void *dtv + * } + * struct pthread *thread + * void *locale + * int errno + * ...cancelation and other int-sized info... + * } + * [pthread structure] + */ +// +//struct tib { +//#if defined(__i386) || defined(__amd64) +// struct tib *__tib_self; +//# define __tib_tcb __tib_self +//#endif +// void *tib_dtv; /* internal to the runtime linker */ +// void *tib_thread; +// void *tib_locale; +// int tib_errno; +// int tib_canceled; +// int tib_cancel_point; +// int tib_cantcancel; +// pid_t tib_tid; +// int tib_thread_flags; /* internal to libpthread */ +// void *tib_atexit; +//}; +// +//#if defined(__i386) || defined(__amd64) +//# define _TIB_PREP(tib) \ +// ((void)((tib)->__tib_self = (tib))) +//#endif +// +//#define TIB_EXTRA_ALIGN sizeof(void *) +// +//#else +//# error "unknown TLS variant" +//#endif + +/* nothing to do by default */ +#ifndef _TIB_PREP +# define _TIB_PREP(tib) ((void)0) +#endif + +#define TIB_INIT(tib, dtv, thread) do { \ + (tib)->tib_thread = (thread); \ + (tib)->tib_atexit = NULL; \ + (tib)->tib_locale = NULL; \ + (tib)->tib_cantcancel = 0; \ + (tib)->tib_cancel_point = 0; \ + (tib)->tib_canceled = 0; \ + (tib)->tib_dtv = (dtv); \ + (tib)->tib_errno = 0; \ + _TIB_PREP(tib); \ + } while (0) + +#ifndef __tib_tcb +# define __tib_tcb tib_dtv +#endif +#define _TIBO_TCB (offsetof(struct tib, __tib_tcb) + TCB_OFFSET) + +#define TCB_TO_TIB(tcb) ((struct tib *)((char *)(tcb) - _TIBO_TCB)) +#define TIB_TO_TCB(tib) ((char *)(tib) + _TIBO_TCB) +#define TIB_GET() TCB_TO_TIB(TCB_GET()) + + +void *_dl_allocate_tib(size_t _extra); +void _dl_free_tib(void *_tib, size_t _extra); + +/* The actual syscalls */ +void *__get_tcb(void); +void __set_tcb(void *_tcb); + +#endif /* _TIB_H_ */ diff --git a/test/test_pthread.c b/test/test_pthread.c new file mode 100644 index 00000000..afb4567e --- /dev/null +++ b/test/test_pthread.c @@ -0,0 +1,29 @@ +#include + +// Test threads +void test_thread() { + pthread_attr_t attr; + pthread_t thread; + + pthread_attr_init(&attr); + pthread_create(&thread, &attr, NULL, NULL); +} + +// Test mutexes +void test_mutex() { + pthread_mutex_t mutex; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutex_init(&mutex, &attr); + pthread_mutex_lock(&mutex); + pthread_mutex_unlock(&mutex); + pthread_mutex_trylock(&mutex); + pthread_mutex_unlock(&mutex); + pthread_mutex_destroy(&mutex); +} + +int main() { + test_thread(); + test_mutex(); +}