From 33574c17eefcf326c1cd30eb9f915ad26d3d9ef2 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 2 Apr 2018 01:43:22 +0200 Subject: hurd: Add hurd thread library Contributed by Agustina Arzille Amos Jeffries David Michael Marco Gerards Marcus Brinkmann Neal H. Walfield Pino Toscano Richard Braun Roland McGrath Samuel Thibault Thomas DiModica Thomas Schwinge * htl: New directory. * sysdeps/htl: New directory. * sysdeps/hurd/htl: New directory. * sysdeps/i386/htl: New directory. * sysdeps/mach/htl: New directory. * sysdeps/mach/hurd/htl: New directory. * sysdeps/mach/hurd/i386/htl: New directory. * nscd/Depend, resolv/Depend, rt/Depend: Add htl dependency. * sysdeps/mach/hurd/i386/Implies: Add mach/hurd/i386/htl imply. * sysdeps/mach/hurd/i386/libpthread.abilist: New file. --- htl/Makefile | 237 +++++++++++++++++ htl/Versions | 156 +++++++++++ htl/alloca_cutoff.c | 26 ++ htl/configure | 2 + htl/configure.in | 4 + htl/cthreads-compat.c | 101 +++++++ htl/forward.c | 283 ++++++++++++++++++++ htl/libc_pthread_init.c | 33 +++ htl/libpthread.a | 22 ++ htl/libpthread_pic.a | 22 ++ htl/lockfile.c | 60 +++++ htl/pt-alloc.c | 214 +++++++++++++++ htl/pt-cancel.c | 62 +++++ htl/pt-cleanup.c | 27 ++ htl/pt-create.c | 246 +++++++++++++++++ htl/pt-dealloc.c | 68 +++++ htl/pt-detach.c | 79 ++++++ htl/pt-exit.c | 111 ++++++++ htl/pt-getattr.c | 51 ++++ htl/pt-initialize.c | 83 ++++++ htl/pt-internal.h | 324 +++++++++++++++++++++++ htl/pt-join.c | 75 ++++++ htl/pt-self.c | 33 +++ htl/pt-setcancelstate.c | 46 ++++ htl/pt-setcanceltype.c | 46 ++++ htl/pt-sigmask.c | 31 +++ htl/pt-spin-inlines.c | 33 +++ htl/pt-testcancel.c | 35 +++ htl/pt-yield.c | 26 ++ htl/shlib-versions | 1 + htl/tests/Makefile | 40 +++ htl/tests/README | 6 + htl/tests/test-1.c | 68 +++++ htl/tests/test-10.c | 62 +++++ htl/tests/test-11.c | 159 +++++++++++ htl/tests/test-12.c | 45 ++++ htl/tests/test-13.c | 82 ++++++ htl/tests/test-14.c | 60 +++++ htl/tests/test-15.c | 102 +++++++ htl/tests/test-16.c | 87 ++++++ htl/tests/test-17.c | 73 +++++ htl/tests/test-2.c | 56 ++++ htl/tests/test-3.c | 71 +++++ htl/tests/test-4.c | 102 +++++++ htl/tests/test-5.c | 91 +++++++ htl/tests/test-6.c | 114 ++++++++ htl/tests/test-7.c | 89 +++++++ htl/tests/test-8.c | 78 ++++++ htl/tests/test-9.c | 104 ++++++++ htl/tests/test-__pthread_destroy_specific-skip.c | 100 +++++++ 50 files changed, 4126 insertions(+) create mode 100644 htl/Makefile create mode 100644 htl/Versions create mode 100644 htl/alloca_cutoff.c create mode 100644 htl/configure create mode 100644 htl/configure.in create mode 100644 htl/cthreads-compat.c create mode 100644 htl/forward.c create mode 100644 htl/libc_pthread_init.c create mode 100644 htl/libpthread.a create mode 100644 htl/libpthread_pic.a create mode 100644 htl/lockfile.c create mode 100644 htl/pt-alloc.c create mode 100644 htl/pt-cancel.c create mode 100644 htl/pt-cleanup.c create mode 100644 htl/pt-create.c create mode 100644 htl/pt-dealloc.c create mode 100644 htl/pt-detach.c create mode 100644 htl/pt-exit.c create mode 100644 htl/pt-getattr.c create mode 100644 htl/pt-initialize.c create mode 100644 htl/pt-internal.h create mode 100644 htl/pt-join.c create mode 100644 htl/pt-self.c create mode 100644 htl/pt-setcancelstate.c create mode 100644 htl/pt-setcanceltype.c create mode 100644 htl/pt-sigmask.c create mode 100644 htl/pt-spin-inlines.c create mode 100644 htl/pt-testcancel.c create mode 100644 htl/pt-yield.c create mode 100644 htl/shlib-versions create mode 100644 htl/tests/Makefile create mode 100644 htl/tests/README create mode 100644 htl/tests/test-1.c create mode 100644 htl/tests/test-10.c create mode 100644 htl/tests/test-11.c create mode 100644 htl/tests/test-12.c create mode 100644 htl/tests/test-13.c create mode 100644 htl/tests/test-14.c create mode 100644 htl/tests/test-15.c create mode 100644 htl/tests/test-16.c create mode 100644 htl/tests/test-17.c create mode 100644 htl/tests/test-2.c create mode 100644 htl/tests/test-3.c create mode 100644 htl/tests/test-4.c create mode 100644 htl/tests/test-5.c create mode 100644 htl/tests/test-6.c create mode 100644 htl/tests/test-7.c create mode 100644 htl/tests/test-8.c create mode 100644 htl/tests/test-9.c create mode 100644 htl/tests/test-__pthread_destroy_specific-skip.c (limited to 'htl') diff --git a/htl/Makefile b/htl/Makefile new file mode 100644 index 0000000000..3bde5f0800 --- /dev/null +++ b/htl/Makefile @@ -0,0 +1,237 @@ +# +# Copyright (C) 1994-2018 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, or (at +# your option) any later version. +# +# This program 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +subdir := htl + +srcdir = . + +MICROKERNEL := mach +SYSDEPS := lockfile + +LCLHDRS := + +libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate \ + pt-attr-getguardsize pt-attr-getinheritsched \ + pt-attr-getschedparam pt-attr-getschedpolicy pt-attr-getscope \ + pt-attr-getstack pt-attr-getstackaddr pt-attr-getstacksize \ + pt-attr-init pt-attr-setdetachstate pt-attr-setguardsize \ + pt-attr-setinheritsched pt-attr-setschedparam \ + pt-attr-setschedpolicy pt-attr-setscope pt-attr-setstack \ + pt-attr-setstackaddr pt-attr-setstacksize \ + \ + pt-barrier-destroy pt-barrier-init pt-barrier-wait \ + pt-barrier pt-barrierattr-destroy pt-barrierattr-init \ + pt-barrierattr-getpshared pt-barrierattr-setpshared \ + \ + pt-destroy-specific pt-init-specific \ + pt-key-create pt-key-delete \ + pt-getspecific pt-setspecific \ + \ + pt-once \ + \ + pt-alloc \ + pt-create \ + pt-getattr \ + pt-equal \ + pt-dealloc \ + pt-detach \ + pt-exit \ + pt-initialize \ + pt-join \ + pt-self \ + pt-sigmask \ + pt-spin-inlines \ + pt-cleanup \ + pt-setcancelstate \ + pt-setcanceltype \ + pt-testcancel \ + pt-cancel \ + \ + pt-mutexattr \ + pt-mutexattr-destroy pt-mutexattr-init \ + pt-mutexattr-getprioceiling pt-mutexattr-getprotocol \ + pt-mutexattr-getpshared pt-mutexattr-gettype \ + pt-mutexattr-setprioceiling pt-mutexattr-setprotocol \ + pt-mutexattr-setpshared pt-mutexattr-settype \ + pt-mutexattr-getrobust pt-mutexattr-setrobust \ + \ + pt-mutex-init pt-mutex-destroy \ + pt-mutex-lock pt-mutex-trylock pt-mutex-timedlock \ + pt-mutex-unlock \ + pt-mutex-transfer-np \ + pt-mutex-getprioceiling pt-mutex-setprioceiling \ + pt-mutex-consistent \ + \ + pt-rwlock-attr \ + pt-rwlockattr-init pt-rwlockattr-destroy \ + pt-rwlockattr-getpshared pt-rwlockattr-setpshared \ + \ + pt-rwlock-init pt-rwlock-destroy \ + pt-rwlock-rdlock pt-rwlock-tryrdlock \ + pt-rwlock-trywrlock pt-rwlock-wrlock \ + pt-rwlock-timedrdlock pt-rwlock-timedwrlock \ + pt-rwlock-unlock \ + \ + pt-cond \ + pt-condattr-init pt-condattr-destroy \ + pt-condattr-getclock pt-condattr-getpshared \ + pt-condattr-setclock pt-condattr-setpshared \ + \ + pt-cond-destroy pt-cond-init \ + pt-cond-brdcast \ + pt-cond-signal \ + pt-cond-wait \ + pt-cond-timedwait \ + pt-hurd-cond-wait \ + pt-hurd-cond-timedwait \ + \ + pt-stack-alloc \ + pt-thread-alloc \ + pt-thread-start \ + pt-thread-terminate \ + pt-startup \ + \ + pt-getconcurrency pt-setconcurrency \ + \ + pt-block \ + pt-timedblock \ + pt-wakeup \ + pt-docancel \ + pt-sysdep \ + pt-setup \ + pt-machdep \ + pt-spin \ + \ + pt-sigstate-init \ + pt-sigstate-destroy \ + pt-sigstate \ + \ + pt-atfork \ + old_pt-atfork \ + pt-kill \ + pt-getcpuclockid \ + \ + pt-getschedparam pt-setschedparam pt-setschedprio \ + pt-yield \ + \ + sem-close sem-destroy sem-getvalue sem-init sem-open \ + sem-post sem-timedwait sem-trywait sem-unlink \ + sem-wait \ + \ + shm-directory \ + \ + cthreads-compat \ + $(SYSDEPS) + +libpthread-static-only-routines = pt-atfork + +headers := \ + pthread.h \ + semaphore.h \ + \ + bits/pthread.h \ + bits/pthread-np.h \ + bits/pthreadtypes.h \ + bits/pthreadtypes-arch.h \ + bits/thread-shared-types.h \ + bits/types/struct___pthread_mutex.h \ + bits/types/struct___pthread_cond.h \ + bits/types/struct___pthread_condattr.h \ + bits/types/__pthread_spinlock_t.h \ + bits/spin-lock-inline.h \ + bits/cancelation.h \ + bits/types/struct___pthread_attr.h \ + bits/types/struct___pthread_barrierattr.h \ + bits/types/struct___pthread_barrier.h \ + bits/types/__pthread_key.h \ + bits/types/struct___pthread_once.h \ + bits/types/struct___pthread_mutexattr.h \ + bits/types/struct___pthread_rwlock.h \ + bits/types/struct___pthread_rwlockattr.h \ + bits/semaphore.h + +distribute := + +routines := forward libc_pthread_init alloca_cutoff +shared-only-routines = forward + +extra-libs := libpthread +extra-libs-others := $(extra-libs) +install-lib := libpthread.so + +include ../Makeconfig + +CFLAGS-lockfile.c = -D_IO_MTSAFE_IO + +all: # Make this the default target; it will be defined in Rules. + +subdir_install: $(inst_libdir)/libpthread2.a + +# XXX: If $(inst_libdir)/libpthread2.a is installed and +# $(inst_libdir)/libpthread is not, we can have some issues. +.PHONY: $(inst_libdir)/libpthread.a $(inst_libdir)/libpthread_pic.a + +# XXX: These rules are a hack. But it is better than messing with +# ../Makeconf at the moment. Note that the linker scripts +# $(srcdir)/libpthread.a and $(srcdir)/libpthread_pic.a get overwritten +# when building in $(srcdir) and not a seperate build directory. +$(inst_libdir)/libpthread2.a: $(inst_libdir)/libpthread.a + mv $< $@ + $(INSTALL_DATA) $(srcdir)/libpthread.a $< + +$(inst_libdir)/libpthread2_pic.a: $(inst_libdir)/libpthread_pic.a + mv $< $@ + $(INSTALL_DATA) $(srcdir)/libpthread_pic.a $< + +libc-link.so = $(common-objpfx)libc.so + +extra-B-pthread.so = -B$(common-objpfx)htl/ + +include ../Rules + +ifeq (yes,$(build-shared)) +# What we install as libpthread.so for programs to link against is in fact a +# link script. It contains references for the various libraries we need. +# The libpthread.so object is not complete since some functions are only +# defined in libpthread_nonshared.a. +# We need to use absolute paths since otherwise local copies (if they exist) +# of the files are taken by the linker. +install: $(inst_libdir)/libpthread.so + +$(inst_libdir)/libpthread.so: $(common-objpfx)format.lds \ + $(objpfx)libpthread.so$(libpthread.so-version) \ + $(inst_libdir)/$(patsubst %,$(libtype.oS),\ + $(libprefix)pthread) \ + $(+force) + (echo '/* GNU ld script';\ + echo ' Use the shared library, but some functions are only in';\ + echo ' the static library, so try that secondarily. */';\ + cat $<; \ + echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \ + '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\ + ')' \ + ) > $@.new + mv -f $@.new $@ + +$(addprefix $(objpfx), \ + $(filter-out $(tests-static) $(xtests-static) $(tests-reverse) \ + $(tests-nolibpthread), \ + $(tests) $(xtests) $(test-srcs))): $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a +endif + +generated += libpthread_nonshared.a diff --git a/htl/Versions b/htl/Versions new file mode 100644 index 0000000000..6a63a1b8a1 --- /dev/null +++ b/htl/Versions @@ -0,0 +1,156 @@ +libc { + GLIBC_2.21 { + pthread_attr_destroy; pthread_attr_getdetachstate; + pthread_attr_getinheritsched; pthread_attr_getschedparam; + pthread_attr_getschedpolicy; pthread_attr_getscope; pthread_attr_init; + pthread_attr_setdetachstate; pthread_attr_setinheritsched; + pthread_attr_setschedparam; pthread_attr_setschedpolicy; + pthread_attr_setscope; + pthread_condattr_destroy; pthread_condattr_init; + pthread_cond_broadcast; pthread_cond_destroy; + pthread_cond_init; pthread_cond_signal; pthread_cond_wait; + pthread_cond_timedwait; + pthread_equal; + pthread_exit; pthread_getschedparam; pthread_setschedparam; + pthread_mutex_destroy; pthread_mutex_init; + pthread_mutex_lock; pthread_mutex_trylock; pthread_mutex_unlock; + pthread_self; pthread_setcancelstate; pthread_setcanceltype; + __pthread_get_cleanup_stack; + } + GLIBC_2.22 { + __register_atfork; + } + GLIBC_PRIVATE { + __libc_alloca_cutoff; + __libc_pthread_init; + } +} + +libpthread { + GLIBC_2.2.6 { + _IO_flockfile; _IO_ftrylockfile; _IO_funlockfile; + } + GLIBC_2.12 { + __pthread_errorcheck_mutexattr; __pthread_recursive_mutexattr; + + __pthread_get_cleanup_stack; + + __pthread_mutex_transfer_np; + + _pthread_mutex_destroy; _pthread_mutex_init; + _pthread_mutex_lock; _pthread_mutex_trylock; _pthread_mutex_unlock; + _pthread_rwlock_destroy; _pthread_rwlock_init; + + _cthread_init_routine; + + cthread_detach; + cthread_fork; + cthread_keycreate; + cthread_getspecific; + cthread_setspecific; + __mutex_lock_solid; + __mutex_unlock_solid; + _cthreads_flockfile; + _cthreads_ftrylockfile; + _cthreads_funlockfile; + + flockfile; ftrylockfile; funlockfile; + + pthread_atfork; + + 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_cond_broadcast; pthread_cond_destroy; pthread_cond_init; + pthread_cond_signal; pthread_cond_timedwait; pthread_cond_wait; + + pthread_condattr_destroy; pthread_condattr_getclock; + pthread_condattr_getpshared; pthread_condattr_init; + pthread_condattr_setclock; pthread_condattr_setpshared; + + pthread_create; pthread_detach; pthread_equal; pthread_exit; + + pthread_getattr_np; + + pthread_getconcurrency; pthread_getcpuclockid; + pthread_getschedparam; pthread_getspecific; + + pthread_join; + + pthread_key_create; pthread_key_delete; + __pthread_key_create; + + pthread_kill; + __pthread_kill; + + pthread_mutex_destroy; pthread_mutex_getprioceiling; + pthread_mutex_init; pthread_mutex_lock; pthread_mutex_setprioceiling; + pthread_mutex_timedlock; pthread_mutex_transfer_np; + pthread_mutex_trylock; pthread_mutex_unlock; + + pthread_mutexattr_destroy; pthread_mutexattr_getprioceiling; + pthread_mutexattr_getprotocol; pthread_mutexattr_getpshared; + pthread_mutexattr_gettype; pthread_mutexattr_init; + pthread_mutexattr_setprioceiling; pthread_mutexattr_setprotocol; + pthread_mutexattr_setpshared; pthread_mutexattr_settype; + + pthread_once; + + 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_self; + __pthread_self; + + pthread_setcancelstate; pthread_setcanceltype; + pthread_setconcurrency; pthread_setschedparam; + pthread_setschedprio; pthread_setspecific; + + pthread_sigmask; + pthread_testcancel; + pthread_yield; + + sem_close; sem_destroy; sem_getvalue; sem_init; sem_open; sem_post; + sem_timedwait; sem_trywait; sem_unlink; sem_wait; + + pthread_spin_destroy; pthread_spin_init; pthread_spin_lock; + pthread_spin_trylock; pthread_spin_unlock; + __pthread_spin_destroy; __pthread_spin_init; + __pthread_spin_lock; __pthread_spin_trylock; __pthread_spin_unlock; + _pthread_spin_lock; + } + GLIBC_2.21 { + pthread_hurd_cond_wait_np; + pthread_hurd_cond_timedwait_np; + } + GLIBC_PRIVATE { + __shm_directory; + __pthread_threads; + + __cthread_detach; + __cthread_fork; + __cthread_keycreate; + __cthread_getspecific; + __cthread_setspecific; + __pthread_getattr_np; + __pthread_attr_getstack; + } +} diff --git a/htl/alloca_cutoff.c b/htl/alloca_cutoff.c new file mode 100644 index 0000000000..4c183bd7fa --- /dev/null +++ b/htl/alloca_cutoff.c @@ -0,0 +1,26 @@ +/* Allocate a new thread structure. + Copyright (C) 2015-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +int +__libc_alloca_cutoff (size_t size) +{ + return size <= 65536; +} +libc_hidden_def (__libc_alloca_cutoff) diff --git a/htl/configure b/htl/configure new file mode 100644 index 0000000000..5983490dde --- /dev/null +++ b/htl/configure @@ -0,0 +1,2 @@ +libc_add_on_canonical=libpthread +libc_add_on_subdirs=. diff --git a/htl/configure.in b/htl/configure.in new file mode 100644 index 0000000000..4e140b1197 --- /dev/null +++ b/htl/configure.in @@ -0,0 +1,4 @@ +GLIBC_PROVIDES + +libc_add_on_canonical=libpthread +libc_add_on_subdirs=. diff --git a/htl/cthreads-compat.c b/htl/cthreads-compat.c new file mode 100644 index 0000000000..042ed64e1d --- /dev/null +++ b/htl/cthreads-compat.c @@ -0,0 +1,101 @@ +/* Compatibility routines for cthreads. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include + +#define CTHREAD_KEY_INVALID (__cthread_key_t) -1 + +void +__cthread_detach (__cthread_t thread) +{ + int err; + + err = pthread_detach ((pthread_t) thread); + assert_perror (err); +} +weak_alias (__cthread_detach, cthread_detach) + +__cthread_t +__cthread_fork (__cthread_fn_t func, void *arg) +{ + pthread_t thread; + int err; + + err = pthread_create (&thread, NULL, func, arg); + assert_perror (err); + + return (__cthread_t) thread; +} +weak_alias (__cthread_fork, cthread_fork) + +int +__cthread_keycreate (__cthread_key_t *key) +{ + error_t err; + + err = pthread_key_create (key, 0); + if (err) + { + errno = err; + *key = CTHREAD_KEY_INVALID; + err = -1; + } + + return err; +} +weak_alias (__cthread_keycreate, cthread_keycreate) + +int +__cthread_getspecific (__cthread_key_t key, void **val) +{ + *val = pthread_getspecific (key); + return 0; +} +weak_alias (__cthread_getspecific, cthread_getspecific) + +int +__cthread_setspecific (__cthread_key_t key, void *val) +{ + error_t err; + + err = pthread_setspecific (key, (const void *) val); + if (err) + { + errno = err; + err = -1; + } + + return err; +} +weak_alias (__cthread_setspecific, cthread_setspecific) + +void +__mutex_lock_solid (void *lock) +{ + __pthread_mutex_lock (lock); +} + +void +__mutex_unlock_solid (void *lock) +{ + if (__pthread_spin_trylock (lock) != 0) + /* Somebody already got the lock, that one will manage waking up others */ + return; + __pthread_mutex_unlock (lock); +} diff --git a/htl/forward.c b/htl/forward.c new file mode 100644 index 0000000000..cb36ae2cb7 --- /dev/null +++ b/htl/forward.c @@ -0,0 +1,283 @@ +/* Libc stubs for pthread functions. Hurd pthread version. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +/* Pointers to the libc functions. */ +struct pthread_functions __libc_pthread_functions attribute_hidden; +int __libc_pthread_functions_init attribute_hidden; + + +#define FORWARD2(name, rettype, decl, params, defaction) \ +rettype \ +name decl \ +{ \ + if (!__libc_pthread_functions_init) \ + defaction; \ + \ + return PTHFCT_CALL (ptr_##name, params); \ +} + +/* Same as FORWARD2, only without return. */ +#define FORWARD_NORETURN(name, rettype, decl, params, defaction) \ +rettype \ +name decl \ +{ \ + if (!__libc_pthread_functions_init) \ + defaction; \ + \ + PTHFCT_CALL (ptr_##name, params); \ +} + +#define FORWARD(name, decl, params, defretval) \ + FORWARD2 (name, int, decl, params, return defretval) + +FORWARD (pthread_attr_destroy, (pthread_attr_t *attr), (attr), 0) + +FORWARD (pthread_attr_init, (pthread_attr_t *attr), (attr), 0) + +FORWARD (pthread_attr_getdetachstate, + (const pthread_attr_t *attr, int *detachstate), (attr, detachstate), + 0) +FORWARD (pthread_attr_setdetachstate, (pthread_attr_t *attr, int detachstate), + (attr, detachstate), 0) + +FORWARD (pthread_attr_getinheritsched, + (const pthread_attr_t *attr, int *inherit), (attr, inherit), 0) +FORWARD (pthread_attr_setinheritsched, (pthread_attr_t *attr, int inherit), + (attr, inherit), 0) + +FORWARD (pthread_attr_getschedparam, + (const pthread_attr_t *attr, struct sched_param *param), + (attr, param), 0) +FORWARD (pthread_attr_setschedparam, + (pthread_attr_t *attr, const struct sched_param *param), + (attr, param), 0) + +FORWARD (pthread_attr_getschedpolicy, + (const pthread_attr_t *attr, int *policy), (attr, policy), 0) +FORWARD (pthread_attr_setschedpolicy, (pthread_attr_t *attr, int policy), + (attr, policy), 0) + +FORWARD (pthread_attr_getscope, + (const pthread_attr_t *attr, int *scope), (attr, scope), 0) +FORWARD (pthread_attr_setscope, (pthread_attr_t *attr, int scope), + (attr, scope), 0) + + +FORWARD (pthread_condattr_destroy, (pthread_condattr_t *attr), (attr), 0) +FORWARD (pthread_condattr_init, (pthread_condattr_t *attr), (attr), 0) + + +FORWARD (pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0) +FORWARD (pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0) +FORWARD (pthread_cond_init, + (pthread_cond_t *cond, const pthread_condattr_t *cond_attr), + (cond, cond_attr), 0) +FORWARD (pthread_cond_signal, (pthread_cond_t *cond), (cond), 0) +FORWARD (pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex), + (cond, mutex), 0) +FORWARD (pthread_cond_timedwait, + (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime), (cond, mutex, abstime), 0) + +FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2), + (thread1, thread2), 1) + + +/* Use an alias to avoid warning, as pthread_exit is declared noreturn. */ +FORWARD_NORETURN (__pthread_exit, void, (void *retval), (retval), + exit (EXIT_SUCCESS)) +strong_alias (__pthread_exit, pthread_exit); + + +FORWARD (pthread_getschedparam, + (pthread_t target_thread, int *policy, struct sched_param *param), + (target_thread, policy, param), 0) +FORWARD (pthread_setschedparam, + (pthread_t target_thread, int policy, + const struct sched_param *param), (target_thread, policy, param), 0) + + +FORWARD (pthread_mutex_destroy, (pthread_mutex_t *mutex), (mutex), 0) + +FORWARD (pthread_mutex_init, + (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr), + (mutex, mutexattr), 0) + +FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0) + +FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0) + + +FORWARD2 (pthread_self, pthread_t, (void), (), return 0) + + +FORWARD (__pthread_setcancelstate, (int state, int *oldstate), + (state, oldstate), 0) +strong_alias (__pthread_setcancelstate, pthread_setcancelstate); + +FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0) + +struct __pthread_cancelation_handler *dummy_list; +FORWARD2 (__pthread_get_cleanup_stack, struct __pthread_cancelation_handler **, + (void), (), return &dummy_list); + + +/* Fork interaction */ + +struct atfork +{ + void (*prepare) (void); + void (*parent) (void); + void (*child) (void); + void *dso_handle; + struct atfork *prev; + struct atfork *next; +}; + +/* TODO: better locking */ +__libc_lock_define_initialized (static, atfork_lock); +static struct atfork *fork_handlers, *fork_last_handler; + +static void +atfork_pthread_prepare (void) +{ + struct atfork *handlers, *last_handler; + + __libc_lock_lock (atfork_lock); + handlers = fork_handlers; + last_handler = fork_last_handler; + __libc_lock_unlock (atfork_lock); + + if (last_handler == NULL) + return; + + while (1) + { + if (last_handler->prepare != NULL) + last_handler->prepare (); + if (last_handler == handlers) + break; + last_handler = last_handler->prev; + } +} +text_set_element (_hurd_atfork_prepare_hook, atfork_pthread_prepare); + +static void +atfork_pthread_parent (void) +{ + struct atfork *handlers; + + __libc_lock_lock (atfork_lock); + handlers = fork_handlers; + __libc_lock_unlock (atfork_lock); + + while (handlers != NULL) + { + if (handlers->parent != NULL) + handlers->parent (); + handlers = handlers->next; + } +} +text_set_element (_hurd_atfork_parent_hook, atfork_pthread_parent); + +static void +atfork_pthread_child (void) +{ + struct atfork *handlers; + + __libc_lock_lock (atfork_lock); + handlers = fork_handlers; + __libc_lock_unlock (atfork_lock); + + while (handlers != NULL) + { + if (handlers->child != NULL) + handlers->child (); + handlers = handlers->next; + } +} +text_set_element (_hurd_atfork_child_hook, atfork_pthread_child); + +int +__register_atfork (void (*prepare) (void), + void (*parent) (void), + void (*child) (void), + void *dso_handle) +{ + struct atfork *new = malloc (sizeof (*new)); + if (new == NULL) + return errno; + + new->prepare = prepare; + new->parent = parent; + new->child = child; + new->dso_handle = dso_handle; + new->prev = NULL; + + __libc_lock_lock (atfork_lock); + new->next = fork_handlers; + if (fork_handlers != NULL) + fork_handlers->prev = new; + fork_handlers = new; + if (fork_last_handler == NULL) + fork_last_handler = new; + __libc_lock_unlock (atfork_lock); + + return 0; +} +libc_hidden_def (__register_atfork) + +void +__unregister_atfork (void *dso_handle) +{ + struct atfork **handlers, *prev = NULL, *next; + __libc_lock_lock (atfork_lock); + handlers = &fork_handlers; + while (*handlers != NULL) + { + if ((*handlers)->dso_handle == dso_handle) + { + /* Drop this handler from the list. */ + if (*handlers == fork_last_handler) + { + /* Was last, new last is prev, if any. */ + fork_last_handler = prev; + } + + next = (*handlers)->next; + if (next != NULL) + next->prev = prev; + *handlers = next; + } + else + { + /* Just proceed to next handler. */ + prev = *handlers; + handlers = &prev->next; + } + } + __libc_lock_unlock (atfork_lock); +} diff --git a/htl/libc_pthread_init.c b/htl/libc_pthread_init.c new file mode 100644 index 0000000000..b6e96827a5 --- /dev/null +++ b/htl/libc_pthread_init.c @@ -0,0 +1,33 @@ +/* libc initialization for libpthread. Hurd pthread version. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C 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. + + The GNU C 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 the GNU C Library; if not, see + . */ + +#include +#include + +void +__libc_pthread_init (const struct pthread_functions *functions) +{ +#ifdef SHARED + /* We copy the content of the variable pointed to by the FUNCTIONS + parameter to one in libc.so since this means access to the array + can be done with one memory access instead of two. */ + memcpy (&__libc_pthread_functions, functions, + sizeof (__libc_pthread_functions)); + __libc_pthread_functions_init = 1; +#endif +} diff --git a/htl/libpthread.a b/htl/libpthread.a new file mode 100644 index 0000000000..e5bd2cc229 --- /dev/null +++ b/htl/libpthread.a @@ -0,0 +1,22 @@ +/* pthread initializer is weak in glibc. It must be included if glibc + is to start threading. */ +EXTERN(_cthread_init_routine) + +/* Weak references in glibc that must be filled if glibc is to be + thread safe. */ +EXTERN(cthread_detach) +EXTERN(cthread_fork) +EXTERN(cthread_keycreate) +EXTERN(cthread_getspecific) +EXTERN(cthread_setspecific) +EXTERN(__mutex_lock_solid) +EXTERN(__mutex_unlock_solid) +/* For libio stream locking. */ +EXTERN(_cthreads_flockfile) +EXTERN(_cthreads_funlockfile) +EXTERN(_cthreads_ftrylockfile) +/* To get the sigthread stack layout on fork */ +EXTERN(pthread_getattr_np) +EXTERN(pthread_attr_getstack) + +GROUP(-lpthread2 -lrt) diff --git a/htl/libpthread_pic.a b/htl/libpthread_pic.a new file mode 100644 index 0000000000..33346b4b39 --- /dev/null +++ b/htl/libpthread_pic.a @@ -0,0 +1,22 @@ +/* pthread initializer is weak in glibc. It must be included if glibc + is to start threading. */ +EXTERN(_cthread_init_routine) + +/* Weak references in glibc that must be filled if glibc is to be + thread safe. */ +EXTERN(cthread_detach) +EXTERN(cthread_fork) +EXTERN(cthread_keycreate) +EXTERN(cthread_getspecific) +EXTERN(cthread_setspecific) +EXTERN(__mutex_lock_solid) +EXTERN(__mutex_unlock_solid) +/* For libio stream locking. */ +EXTERN(_cthreads_flockfile) +EXTERN(_cthreads_funlockfile) +EXTERN(_cthreads_ftrylockfile) +/* To get the sigthread stack layout on fork */ +EXTERN(pthread_getattr_np) +EXTERN(pthread_attr_getstack) + +GROUP(-lpthread2_pic) diff --git a/htl/lockfile.c b/htl/lockfile.c new file mode 100644 index 0000000000..9069496185 --- /dev/null +++ b/htl/lockfile.c @@ -0,0 +1,60 @@ +/* lockfile - Handle locking and unlocking of streams. Hurd pthread version. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include /* Must come before ! */ +#include + +void +_cthreads_flockfile (FILE *fp) +{ + _IO_lock_lock (*fp->_lock); +} + +void +_cthreads_funlockfile (FILE *fp) +{ + _IO_lock_unlock (*fp->_lock); +} + +int +_cthreads_ftrylockfile (FILE *fp) +{ + return __libc_lock_trylock_recursive (*fp->_lock); +} + +#undef _IO_flockfile +#undef _IO_funlockfile +#undef _IO_ftrylockfile +#undef flockfile +#undef funlockfile +#undef ftrylockfile + +void _IO_flockfile (FILE *) + __attribute__ ((alias ("_cthreads_flockfile"))); +void _IO_funlockfile (FILE *) + __attribute__ ((alias ("_cthreads_funlockfile"))); +int _IO_ftrylockfile (FILE *) + __attribute__ ((alias ("_cthreads_ftrylockfile"))); + +void flockfile (FILE *) + __attribute__ ((alias ("_cthreads_flockfile"))); +void funlockfile (FILE *) + __attribute__ ((alias ("_cthreads_funlockfile"))); +int ftrylockfile (FILE *) + __attribute__ ((alias ("_cthreads_ftrylockfile"))); diff --git a/htl/pt-alloc.c b/htl/pt-alloc.c new file mode 100644 index 0000000000..adab790d9d --- /dev/null +++ b/htl/pt-alloc.c @@ -0,0 +1,214 @@ +/* Allocate a new thread structure. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include +#include +#include + +#include + +/* This braindamage is necessary because the standard says that some + of the threads functions "shall fail" if "No thread could be found + corresponding to that specified by the given thread ID." */ + +/* Thread ID lookup table. */ +struct __pthread **__pthread_threads; + +/* The size of the thread ID lookup table. */ +int __pthread_max_threads; + +/* The total number of thread IDs currently in use, or on the list of + available thread IDs. */ +int __pthread_num_threads; + +/* A lock for the table, and the other variables above. */ +pthread_rwlock_t __pthread_threads_lock; + +/* List of thread structures corresponding to free thread IDs. */ +struct __pthread *__pthread_free_threads; +pthread_mutex_t __pthread_free_threads_lock; + +static inline error_t +initialize_pthread (struct __pthread *new) +{ + error_t err; + + err = __pthread_init_specific (new); + if (err) + return err; + + new->nr_refs = 1; + new->cancel_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; + new->cancel_hook = NULL; + new->cancel_hook_arg = NULL; + new->cancel_state = PTHREAD_CANCEL_ENABLE; + new->cancel_type = PTHREAD_CANCEL_DEFERRED; + new->cancel_pending = 0; + + new->state_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; + new->state_cond = (pthread_cond_t) PTHREAD_COND_INITIALIZER; + + new->cancelation_handlers = 0; + + memset (&new->res_state, '\0', sizeof (new->res_state)); + + new->tcb = NULL; + + new->next = 0; + new->prevp = 0; + + return 0; +} + + +/* Allocate a new thread structure and its pthread thread ID (but not + a kernel thread). */ +int +__pthread_alloc (struct __pthread **pthread) +{ + error_t err; + + struct __pthread *new; + struct __pthread **threads; + struct __pthread **old_threads; + int max_threads; + int new_max_threads; + + pthread_mutex_lock (&__pthread_free_threads_lock); + for (new = __pthread_free_threads; new; new = new->next) + { + /* There is no need to take NEW->STATE_LOCK: if NEW is on this + list, then it is protected by __PTHREAD_FREE_THREADS_LOCK + except in __pthread_dealloc where after it is added to the + list (with the lock held), it drops the lock and then sets + NEW->STATE and immediately stops using NEW. */ + if (new->state == PTHREAD_TERMINATED) + { + __pthread_dequeue (new); + break; + } + } + pthread_mutex_unlock (&__pthread_free_threads_lock); + + if (new) + { + if (new->tcb) + { + /* Drop old values */ + _dl_deallocate_tls (new->tcb, 1); + } + + err = initialize_pthread (new); + if (!err) + *pthread = new; + return err; + } + + /* Allocate a new thread structure. */ + new = malloc (sizeof (struct __pthread)); + if (new == NULL) + return ENOMEM; + + err = initialize_pthread (new); + if (err) + { + free (new); + return err; + } + +retry: + __pthread_rwlock_wrlock (&__pthread_threads_lock); + + if (__pthread_num_threads < __pthread_max_threads) + { + /* We have a free slot. Use the slot number plus one as the + thread ID for the new thread. */ + new->thread = 1 + __pthread_num_threads++; + __pthread_threads[new->thread - 1] = NULL; + + __pthread_rwlock_unlock (&__pthread_threads_lock); + + *pthread = new; + return 0; + } +#ifdef PTHREAD_THREADS_MAX + else if (__pthread_num_threads >= PTHREAD_THREADS_MAX) + { + /* We have reached the limit on the number of threads per process. */ + __pthread_rwlock_unlock (&__pthread_threads_lock); + + free (new); + return EAGAIN; + } +#endif + + /* We are going to enlarge the threads table. Save its current + size. We're going to release the lock before doing the necessary + memory allocation, since that's a potentially blocking operation. */ + max_threads = __pthread_max_threads; + + __pthread_rwlock_unlock (&__pthread_threads_lock); + + /* Allocate a new lookup table that's twice as large. */ + new_max_threads + = max_threads > 0 ? max_threads * 2 : _POSIX_THREAD_THREADS_MAX; + threads = malloc (new_max_threads * sizeof (struct __pthread *)); + if (threads == NULL) + { + free (new); + return ENOMEM; + } + + __pthread_rwlock_wrlock (&__pthread_threads_lock); + + /* Check if nobody else has already enlarged the table. */ + if (max_threads != __pthread_max_threads) + { + /* Yep, they did. */ + __pthread_rwlock_unlock (&__pthread_threads_lock); + + /* Free the newly allocated table and try again to allocate a slot. */ + free (threads); + goto retry; + } + + /* Copy over the contents of the old table. */ + memcpy (threads, __pthread_threads, + __pthread_max_threads * sizeof (struct __pthread *)); + + /* Save the location of the old table. We want to deallocate its + storage after we released the lock. */ + old_threads = __pthread_threads; + + /* Replace the table with the new one. */ + __pthread_max_threads = new_max_threads; + __pthread_threads = threads; + + /* And allocate ourselves one of the newly created slots. */ + new->thread = 1 + __pthread_num_threads++; + __pthread_threads[new->thread - 1] = NULL; + + __pthread_rwlock_unlock (&__pthread_threads_lock); + + free (old_threads); + + *pthread = new; + return 0; +} diff --git a/htl/pt-cancel.c b/htl/pt-cancel.c new file mode 100644 index 0000000000..9f877243b9 --- /dev/null +++ b/htl/pt-cancel.c @@ -0,0 +1,62 @@ +/* Cancel a thread. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +#include + +int +pthread_cancel (pthread_t t) +{ + int err = 0; + struct __pthread *p; + + p = __pthread_getid (t); + if (p == NULL) + return ESRCH; + + __pthread_mutex_lock (&p->cancel_lock); + if (p->cancel_pending) + { + __pthread_mutex_unlock (&p->cancel_lock); + return 0; + } + + p->cancel_pending = 1; + + if (p->cancel_state != PTHREAD_CANCEL_ENABLE) + { + __pthread_mutex_unlock (&p->cancel_lock); + return 0; + } + + if (p->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS) + /* CANCEL_LOCK is unlocked by this call. */ + err = __pthread_do_cancel (p); + else + { + if (p->cancel_hook != NULL) + /* Thread blocking on a cancellation point. Invoke hook to unblock. + See __pthread_cond_timedwait_internal. */ + p->cancel_hook (p->cancel_hook_arg); + + __pthread_mutex_unlock (&p->cancel_lock); + } + + return err; +} diff --git a/htl/pt-cleanup.c b/htl/pt-cleanup.c new file mode 100644 index 0000000000..74c86b2bf4 --- /dev/null +++ b/htl/pt-cleanup.c @@ -0,0 +1,27 @@ +/* Add a cancelation handler to the stack. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +#include + +struct __pthread_cancelation_handler ** +__pthread_get_cleanup_stack (void) +{ + return &_pthread_self ()->cancelation_handlers; +} diff --git a/htl/pt-create.c b/htl/pt-create.c new file mode 100644 index 0000000000..f5c06ffdaf --- /dev/null +++ b/htl/pt-create.c @@ -0,0 +1,246 @@ +/* Thread creation. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#if IS_IN (libpthread) +# include +#endif +#ifdef HAVE_USELOCALE +# include +#endif + +/* The total number of pthreads currently active. This is defined + here since it would be really stupid to have a threads-using + program that doesn't call `pthread_create'. */ +unsigned int __pthread_total; + + +/* The entry-point for new threads. */ +static void +entry_point (struct __pthread *self, void *(*start_routine) (void *), void *arg) +{ + ___pthread_self = self; + __resp = &self->res_state; + +#if IS_IN (libpthread) + /* Initialize pointers to locale data. */ + __ctype_init (); +#endif +#ifdef HAVE_USELOCALE + /* A fresh thread needs to be bound to the global locale. */ + uselocale (LC_GLOBAL_LOCALE); +#endif + + __pthread_startup (); + + pthread_exit (start_routine (arg)); +} + +/* Create a thread with attributes given by ATTR, executing + START_ROUTINE with argument ARG. */ +int +pthread_create (pthread_t * thread, const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg) +{ + int err; + struct __pthread *pthread; + + err = __pthread_create_internal (&pthread, attr, start_routine, arg); + if (!err) + *thread = pthread->thread; + else if (err == ENOMEM) + err = EAGAIN; + + return err; +} + +/* Internal version of pthread_create. See comment in + pt-internal.h. */ +int +__pthread_create_internal (struct __pthread **thread, + const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg) +{ + int err; + struct __pthread *pthread; + const struct __pthread_attr *setup; + sigset_t sigset; + size_t stacksize; + + /* Allocate a new thread structure. */ + err = __pthread_alloc (&pthread); + if (err) + goto failed; + + /* Use the default attributes if ATTR is NULL. */ + setup = attr ? attr : &__pthread_default_attr; + + stacksize = setup->__stacksize; + if (stacksize == 0) + { + struct rlimit rlim; + __getrlimit (RLIMIT_STACK, &rlim); + if (rlim.rlim_cur != RLIM_INFINITY) + stacksize = rlim.rlim_cur; + if (stacksize == 0) + stacksize = PTHREAD_STACK_DEFAULT; + } + + /* Initialize the thread state. */ + pthread->state = (setup->__detachstate == PTHREAD_CREATE_DETACHED + ? PTHREAD_DETACHED : PTHREAD_JOINABLE); + + if (setup->__stackaddr) + { + pthread->stackaddr = setup->__stackaddr; + + /* If the user supplied a stack, it is not our responsibility to + setup a stack guard. */ + pthread->guardsize = 0; + pthread->stack = 0; + } + else + { + /* Allocate a stack. */ + err = __pthread_stack_alloc (&pthread->stackaddr, + ((setup->__guardsize + __vm_page_size - 1) + / __vm_page_size) * __vm_page_size + + stacksize); + if (err) + goto failed_stack_alloc; + + pthread->guardsize = setup->__guardsize; + pthread->stack = 1; + } + + pthread->stacksize = stacksize; + + /* Allocate the kernel thread and other required resources. */ + err = __pthread_thread_alloc (pthread); + if (err) + goto failed_thread_alloc; + + pthread->tcb = _dl_allocate_tls (NULL); + if (pthread->tcb == NULL) + { + err = ENOMEM; + goto failed_thread_tls_alloc; + } + pthread->tcb->tcb = pthread->tcb; + + /* And initialize the rest of the machine context. This may include + additional machine- and system-specific initializations that + prove convenient. */ + err = __pthread_setup (pthread, entry_point, start_routine, arg); + if (err) + goto failed_setup; + + /* Initialize the system-specific signal state for the new + thread. */ + err = __pthread_sigstate_init (pthread); + if (err) + goto failed_sigstate; + + /* If the new thread is joinable, add a reference for the caller. */ + if (pthread->state == PTHREAD_JOINABLE) + pthread->nr_refs++; + + /* Set the new thread's signal mask and set the pending signals to + empty. POSIX says: "The signal mask shall be inherited from the + creating thread. The set of signals pending for the new thread + shall be empty." If the currnet thread is not a pthread then we + just inherit the process' sigmask. */ + if (__pthread_num_threads == 1) + err = sigprocmask (0, 0, &sigset); + else + err = __pthread_sigstate (_pthread_self (), 0, 0, &sigset, 0); + assert_perror (err); + + err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1); + assert_perror (err); + + /* Increase the total number of threads. We do this before actually + starting the new thread, since the new thread might immediately + call `pthread_exit' which decreases the number of threads and + calls `exit' if the number of threads reaches zero. Increasing + the number of threads from within the new thread isn't an option + since this thread might return and call `pthread_exit' before the + new thread runs. */ + atomic_increment (&__pthread_total); + + /* Store a pointer to this thread in the thread ID lookup table. We + could use __thread_setid, however, we only lock for reading as no + other thread should be using this entry (we also assume that the + store is atomic). */ + __pthread_rwlock_rdlock (&__pthread_threads_lock); + __pthread_threads[pthread->thread - 1] = pthread; + __pthread_rwlock_unlock (&__pthread_threads_lock); + + /* At this point it is possible to guess our pthread ID. We have to + make sure that all functions taking a pthread_t argument can + handle the fact that this thread isn't really running yet. Since + the new thread might be passed its ID through pthread_create (to + avoid calling pthread_self), read it before starting the thread. */ + *thread = pthread; + + /* Schedule the new thread. */ + err = __pthread_thread_start (pthread); + if (err) + goto failed_starting; + + + return 0; + +failed_starting: + /* If joinable, a reference was added for the caller. */ + if (pthread->state == PTHREAD_JOINABLE) + __pthread_dealloc (pthread); + + __pthread_setid (pthread->thread, NULL); + atomic_decrement (&__pthread_total); +failed_sigstate: + __pthread_sigstate_destroy (pthread); +failed_setup: + _dl_deallocate_tls (pthread->tcb, 1); + pthread->tcb = NULL; +failed_thread_tls_alloc: + __pthread_thread_terminate (pthread); + + /* __pthread_thread_terminate has taken care of deallocating the stack and + the thread structure. */ + goto failed; +failed_thread_alloc: + if (pthread->stack) + __pthread_stack_dealloc (pthread->stackaddr, + ((setup->__guardsize + __vm_page_size - 1) + / __vm_page_size) * __vm_page_size + stacksize); +failed_stack_alloc: + __pthread_dealloc (pthread); +failed: + return err; +} diff --git a/htl/pt-dealloc.c b/htl/pt-dealloc.c new file mode 100644 index 0000000000..15e251ef46 --- /dev/null +++ b/htl/pt-dealloc.c @@ -0,0 +1,68 @@ +/* Deallocate a thread structure. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include + +#include + +#include + +/* List of thread structures corresponding to free thread IDs. */ +extern struct __pthread *__pthread_free_threads; +extern pthread_mutex_t __pthread_free_threads_lock; + + +/* Deallocate the thread structure for PTHREAD. */ +void +__pthread_dealloc (struct __pthread *pthread) +{ + assert (pthread->state != PTHREAD_TERMINATED); + + if (!atomic_decrement_and_test (&pthread->nr_refs)) + return; + + /* Withdraw this thread from the thread ID lookup table. */ + __pthread_setid (pthread->thread, NULL); + + /* Mark the thread as terminated. We broadcast the condition + here to prevent pthread_join from waiting for this thread to + exit where it was never really started. Such a call to + pthread_join is completely bogus, but unfortunately allowed + by the standards. */ + __pthread_mutex_lock (&pthread->state_lock); + if (pthread->state != PTHREAD_EXITED) + __pthread_cond_broadcast (&pthread->state_cond); + __pthread_mutex_unlock (&pthread->state_lock); + + /* We do not actually deallocate the thread structure, but add it to + a list of re-usable thread structures. */ + __pthread_mutex_lock (&__pthread_free_threads_lock); + __pthread_enqueue (&__pthread_free_threads, pthread); + __pthread_mutex_unlock (&__pthread_free_threads_lock); + + /* Setting PTHREAD->STATE to PTHREAD_TERMINATED makes this TCB + available for reuse. After that point, we can no longer assume + that PTHREAD is valid. + + Note that it is safe to not lock this update to PTHREAD->STATE: + the only way that it can now be accessed is in __pthread_alloc, + which reads this variable. */ + pthread->state = PTHREAD_TERMINATED; +} diff --git a/htl/pt-detach.c b/htl/pt-detach.c new file mode 100644 index 0000000000..773ed10722 --- /dev/null +++ b/htl/pt-detach.c @@ -0,0 +1,79 @@ +/* Detach a thread. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include + +#include + +/* Indicate that the storage for THREAD can be reclaimed when it + terminates. */ +int +pthread_detach (pthread_t thread) +{ + struct __pthread *pthread; + int err = 0; + + /* Lookup the thread structure for THREAD. */ + pthread = __pthread_getid (thread); + if (pthread == NULL) + return ESRCH; + + __pthread_mutex_lock (&pthread->state_lock); + + switch (pthread->state) + { + case PTHREAD_JOINABLE: + /* THREAD still running. Mark it as detached such that its + resources can be reclaimed as soon as the thread exits. */ + pthread->state = PTHREAD_DETACHED; + + /* Broadcast the condition. This will make threads that are + waiting to join THREAD continue with hopefully disastrous + consequences instead of blocking indefinitely. */ + pthread_cond_broadcast (&pthread->state_cond); + __pthread_mutex_unlock (&pthread->state_lock); + + __pthread_dealloc (pthread); + break; + + case PTHREAD_EXITED: + __pthread_mutex_unlock (&pthread->state_lock); + + /* THREAD has already exited. PTHREAD remained after the thread + exited in order to provide the exit status, but it turns out + it won't be needed. */ + __pthread_dealloc (pthread); + break; + + case PTHREAD_TERMINATED: + /* Pretend THREAD wasn't there in the first place. */ + __pthread_mutex_unlock (&pthread->state_lock); + err = ESRCH; + break; + + default: + /* Thou shalt not detach non-joinable threads! */ + __pthread_mutex_unlock (&pthread->state_lock); + err = EINVAL; + break; + } + + return err; +} diff --git a/htl/pt-exit.c b/htl/pt-exit.c new file mode 100644 index 0000000000..8f3d755773 --- /dev/null +++ b/htl/pt-exit.c @@ -0,0 +1,111 @@ +/* Thread termination. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include +#include + +#include + +#include + + +/* Terminate the current thread and make STATUS available to any + thread that might join it. */ +void +__pthread_exit (void *status) +{ + struct __pthread *self = _pthread_self (); + struct __pthread_cancelation_handler **handlers; + int oldstate; + + /* Run any cancelation handlers. According to POSIX, the + cancellation cleanup handlers should be called with cancellation + disabled. */ + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate); + + for (handlers = __pthread_get_cleanup_stack (); + *handlers != NULL; + *handlers = (*handlers)->__next) + (*handlers)->__handler ((*handlers)->__arg); + + pthread_setcancelstate (oldstate, &oldstate); + + /* Decrease the number of threads. We use an atomic operation to + make sure that only the last thread calls `exit'. */ + if (atomic_decrement_and_test (&__pthread_total)) + /* We are the last thread. */ + exit (0); + + /* Note that after this point the process can be terminated at any + point if another thread calls `pthread_exit' and happens to be + the last thread. */ + + __pthread_mutex_lock (&self->state_lock); + + if (self->cancel_state == PTHREAD_CANCEL_ENABLE && self->cancel_pending) + status = PTHREAD_CANCELED; + + switch (self->state) + { + default: + assert (!"Consistency error: unexpected self->state"); + abort (); + break; + + case PTHREAD_DETACHED: + __pthread_mutex_unlock (&self->state_lock); + + break; + + case PTHREAD_JOINABLE: + /* We need to stay around for a while since another thread + might want to join us. */ + self->state = PTHREAD_EXITED; + + /* We need to remember the exit status. A thread joining us + might ask for it. */ + self->status = status; + + /* Broadcast the condition. This will wake up threads that are + waiting to join us. */ + __pthread_cond_broadcast (&self->state_cond); + __pthread_mutex_unlock (&self->state_lock); + + break; + } + + /* Destroy any thread specific data. */ + __pthread_destroy_specific (self); + + /* Destroy any signal state. */ + __pthread_sigstate_destroy (self); + + /* Self terminating requires TLS, so defer the release of the TCB until + the thread structure is reused. */ + + /* Release kernel resources, including the kernel thread and the stack, + and drop the self reference. */ + __pthread_thread_terminate (self); + + /* NOTREACHED */ + abort (); +} + +strong_alias (__pthread_exit, pthread_exit); diff --git a/htl/pt-getattr.c b/htl/pt-getattr.c new file mode 100644 index 0000000000..b1ec5e0257 --- /dev/null +++ b/htl/pt-getattr.c @@ -0,0 +1,51 @@ +/* Thread attributes retrieval. + Copyright (C) 2008-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include + +#include + +/* Initialize thread attribute *ATTR with attributes corresponding to the + already running thread THREAD. It shall be called on an uninitialized ATTR + and destroyed with pthread_attr_destroy when no longer needed. */ +int +__pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) +{ + struct __pthread *pthread; + + pthread = __pthread_getid (thread); + if (pthread == NULL) + return ESRCH; + + /* Some attributes (schedparam, inheritsched, contentionscope and schedpolicy) + are not supported yet, so fill them with our default values. */ + *attr = __pthread_default_attr; + + attr->__stackaddr = pthread->stackaddr + + ((pthread->guardsize + __vm_page_size - 1) + / __vm_page_size * __vm_page_size); + attr->__stacksize = pthread->stacksize; + attr->__guardsize = pthread->guardsize; + attr->__detachstate = (pthread->state == PTHREAD_DETACHED + ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE); + + return 0; +} +weak_alias (__pthread_getattr_np, pthread_getattr_np) diff --git a/htl/pt-initialize.c b/htl/pt-initialize.c new file mode 100644 index 0000000000..201810f1ca --- /dev/null +++ b/htl/pt-initialize.c @@ -0,0 +1,83 @@ +/* Initialize pthreads library. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include + +#include +#include + +#include +#include + +#if IS_IN (libpthread) +static const struct pthread_functions pthread_functions = { + .ptr_pthread_attr_destroy = __pthread_attr_destroy, + .ptr_pthread_attr_init = __pthread_attr_init, + .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate, + .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate, + .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched, + .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched, + .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam, + .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam, + .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy, + .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy, + .ptr_pthread_attr_getscope = __pthread_attr_getscope, + .ptr_pthread_attr_setscope = __pthread_attr_setscope, + .ptr_pthread_condattr_destroy = __pthread_condattr_destroy, + .ptr_pthread_condattr_init = __pthread_condattr_init, + .ptr_pthread_cond_broadcast = __pthread_cond_broadcast, + .ptr_pthread_cond_destroy = __pthread_cond_destroy, + .ptr_pthread_cond_init = __pthread_cond_init, + .ptr_pthread_cond_signal = __pthread_cond_signal, + .ptr_pthread_cond_wait = __pthread_cond_wait, + .ptr_pthread_cond_timedwait = __pthread_cond_timedwait, + .ptr_pthread_equal = __pthread_equal, + .ptr___pthread_exit = __pthread_exit, + .ptr_pthread_getschedparam = __pthread_getschedparam, + .ptr_pthread_setschedparam = __pthread_setschedparam, + .ptr_pthread_mutex_destroy = _pthread_mutex_destroy, + .ptr_pthread_mutex_init = _pthread_mutex_init, + .ptr_pthread_mutex_lock = __pthread_mutex_lock, + .ptr_pthread_mutex_trylock = __pthread_mutex_trylock, + .ptr_pthread_mutex_unlock = __pthread_mutex_unlock, + .ptr_pthread_self = __pthread_self, + .ptr___pthread_setcancelstate = __pthread_setcancelstate, + .ptr_pthread_setcanceltype = __pthread_setcanceltype, + .ptr___pthread_get_cleanup_stack = __pthread_get_cleanup_stack, + .ptr_pthread_once = __pthread_once, + .ptr_pthread_rwlock_rdlock = __pthread_rwlock_rdlock, + .ptr_pthread_rwlock_wrlock = __pthread_rwlock_wrlock, + .ptr_pthread_rwlock_unlock = __pthread_rwlock_unlock, + .ptr___pthread_key_create = __pthread_key_create, + .ptr___pthread_getspecific = __pthread_getspecific, + .ptr___pthread_setspecific = __pthread_setspecific, + .ptr__IO_flockfile = _cthreads_flockfile, + .ptr__IO_funlockfile = _cthreads_funlockfile, + .ptr__IO_ftrylockfile = _cthreads_ftrylockfile, +}; +#endif /* IS_IN (libpthread) */ + +/* Initialize the pthreads library. */ +void +___pthread_init (void) +{ +#if IS_IN (libpthread) + __libc_pthread_init (&pthread_functions); +#endif +} diff --git a/htl/pt-internal.h b/htl/pt-internal.h new file mode 100644 index 0000000000..22afc1fcce --- /dev/null +++ b/htl/pt-internal.h @@ -0,0 +1,324 @@ +/* Internal defenitions for pthreads library. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#ifndef _PT_INTERNAL_H +#define _PT_INTERNAL_H 1 + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#if IS_IN (libpthread) +# include +#endif + +/* Thread state. */ +enum pthread_state +{ + /* The thread is running and joinable. */ + PTHREAD_JOINABLE = 0, + /* The thread is running and detached. */ + PTHREAD_DETACHED, + /* A joinable thread exited and its return code is available. */ + PTHREAD_EXITED, + /* The thread structure is unallocated and available for reuse. */ + PTHREAD_TERMINATED +}; + +#ifndef PTHREAD_KEY_MEMBERS +# define PTHREAD_KEY_MEMBERS +#endif + +#ifndef PTHREAD_SYSDEP_MEMBERS +# define PTHREAD_SYSDEP_MEMBERS +#endif + +#if !(IS_IN (libpthread)) +/* Type of the TCB. */ +typedef struct +{ + void *tcb; /* Points to this structure. */ + void *dtv; /* Vector of pointers to TLS data. */ + thread_t self; /* This thread's control port. */ +} tcbhead_t; +#endif /* ! IS_IN (libpthread) */ + +/* This structure describes a POSIX thread. */ +struct __pthread +{ + /* Thread ID. */ + pthread_t thread; + + unsigned int nr_refs; /* Detached threads have a self reference only, + while joinable threads have two references. + These are used to keep the structure valid at + thread destruction. Detaching/joining a thread + drops a reference. */ + + /* Cancellation. */ + pthread_mutex_t cancel_lock; /* Protect cancel_xxx members. */ + void (*cancel_hook) (void *); /* Called to unblock a thread blocking + in a cancellation point (namely, + __pthread_cond_timedwait_internal). */ + void *cancel_hook_arg; + int cancel_state; + int cancel_type; + int cancel_pending; + struct __pthread_cancelation_handler *cancelation_handlers; + + /* Thread stack. */ + void *stackaddr; + size_t stacksize; + size_t guardsize; + int stack; /* Nonzero if the stack was allocated. */ + + /* Exit status. */ + void *status; + + /* Thread state. */ + enum pthread_state state; + pthread_mutex_t state_lock; /* Locks the state. */ + pthread_cond_t state_cond; /* Signalled when the state changes. */ + + /* Resolver state. */ + struct __res_state res_state; + + /* Thread context. */ + struct pthread_mcontext mcontext; + + PTHREAD_KEY_MEMBERS + + PTHREAD_SYSDEP_MEMBERS + + tcbhead_t *tcb; + + /* Queue links. Since PREVP is used to determine if a thread has been + awaken, it must be protected by the queue lock. */ + struct __pthread *next, **prevp; +}; + +/* Enqueue an element THREAD on the queue *HEAD. */ +static inline void +__pthread_enqueue (struct __pthread **head, struct __pthread *thread) +{ + assert (thread->prevp == 0); + + thread->next = *head; + thread->prevp = head; + if (*head) + (*head)->prevp = &thread->next; + *head = thread; +} + +/* Dequeue the element THREAD from the queue it is connected to. */ +static inline void +__pthread_dequeue (struct __pthread *thread) +{ + assert (thread); + assert (thread->prevp); + + if (thread->next) + thread->next->prevp = thread->prevp; + *thread->prevp = thread->next; + thread->prevp = 0; +} + +/* Iterate over QUEUE storing each element in ELEMENT. */ +#define __pthread_queue_iterate(queue, element) \ + for (struct __pthread *__pdi_next = (queue); \ + ((element) = __pdi_next) \ + && ((__pdi_next = __pdi_next->next), \ + 1); \ + ) + +/* Iterate over QUEUE dequeuing each element, storing it in + ELEMENT. */ +#define __pthread_dequeuing_iterate(queue, element) \ + for (struct __pthread *__pdi_next = (queue); \ + ((element) = __pdi_next) \ + && ((__pdi_next = __pdi_next->next), \ + ((element)->prevp = 0), \ + 1); \ + ) + +/* The total number of threads currently active. */ +extern unsigned int __pthread_total; + +/* The total number of thread IDs currently in use, or on the list of + available thread IDs. */ +extern int __pthread_num_threads; + +/* Concurrency hint. */ +extern int __pthread_concurrency; + +/* Array of __pthread structures and its lock. Indexed by the pthread + id minus one. (Why not just use the pthread id? Because some + brain-dead users of the pthread interface incorrectly assume that 0 + is an invalid pthread id.) */ +extern struct __pthread **__pthread_threads; +extern pthread_rwlock_t __pthread_threads_lock; + +#define __pthread_getid(thread) \ + ({ struct __pthread *__t; \ + __pthread_rwlock_rdlock (&__pthread_threads_lock); \ + __t = __pthread_threads[thread - 1]; \ + __pthread_rwlock_unlock (&__pthread_threads_lock); \ + __t; }) + +#define __pthread_setid(thread, pthread) \ + __pthread_rwlock_wrlock (&__pthread_threads_lock); \ + __pthread_threads[thread - 1] = pthread; \ + __pthread_rwlock_unlock (&__pthread_threads_lock); + +/* Similar to pthread_self, but returns the thread descriptor instead + of the thread ID. */ +#ifndef _pthread_self +extern struct __pthread *_pthread_self (void); +#endif + + +/* Initialize the pthreads library. */ +extern void ___pthread_init (void); + +/* Internal version of pthread_create. Rather than return the new + tid, we return the whole __pthread structure in *PTHREAD. */ +extern int __pthread_create_internal (struct __pthread **__restrict pthread, + const pthread_attr_t *__restrict attr, + void *(*start_routine) (void *), + void *__restrict arg); + +/* Allocate a new thread structure and a pthread thread ID (but not a + kernel thread or a stack). THREAD has one reference. */ +extern int __pthread_alloc (struct __pthread **thread); + +/* Deallocate the thread structure. This is the dual of + __pthread_alloc (N.B. it does not call __pthread_stack_dealloc nor + __pthread_thread_terminate). THREAD loses one reference and is + released if the reference counter drops to 0. */ +extern void __pthread_dealloc (struct __pthread *thread); + + +/* Allocate a stack of size STACKSIZE. The stack base shall be + returned in *STACKADDR. */ +extern int __pthread_stack_alloc (void **stackaddr, size_t stacksize); + +/* Deallocate the stack STACKADDR of size STACKSIZE. */ +extern void __pthread_stack_dealloc (void *stackaddr, size_t stacksize); + + +/* Setup thread THREAD's context. */ +extern int __pthread_setup (struct __pthread *__restrict thread, + void (*entry_point) (struct __pthread *, + void *(*)(void *), + void *), + void *(*start_routine) (void *), + void *__restrict arg); + + +/* Allocate a kernel thread (and any miscellaneous system dependent + resources) for THREAD; it must not be placed on the run queue. */ +extern int __pthread_thread_alloc (struct __pthread *thread); + +/* Start THREAD making it eligible to run. */ +extern int __pthread_thread_start (struct __pthread *thread); + +/* Terminate the kernel thread associated with THREAD, and deallocate its + stack as well as any other kernel resource associated with it. + In addition, THREAD looses one reference. + + This function can be called by any thread, including the target thread. + Since some resources that are destroyed along the kernel thread are + stored in thread-local variables, the conditions required for this + function to behave correctly are a bit unusual : as long as the target + thread hasn't been started, any thread can terminate it, but once it + has started, no other thread can terminate it, so that thread-local + variables created by that thread are correctly released. */ +extern void __pthread_thread_terminate (struct __pthread *thread); + + +/* Called by a thread just before it calls the provided start + routine. */ +extern void __pthread_startup (void); + +/* Block THREAD. */ +extern void __pthread_block (struct __pthread *thread); + +/* Block THREAD until *ABSTIME is reached. */ +extern error_t __pthread_timedblock (struct __pthread *__restrict thread, + const struct timespec *__restrict abstime, + clockid_t clock_id); + +/* Wakeup THREAD. */ +extern void __pthread_wakeup (struct __pthread *thread); + + +/* Perform a cancelation. The CANCEL_LOCK member of the given thread must + be locked before calling this function, which must unlock it. */ +extern int __pthread_do_cancel (struct __pthread *thread); + + +/* Initialize the thread specific data structures. THREAD must be the + calling thread. */ +extern error_t __pthread_init_specific (struct __pthread *thread); + +/* Call the destructors on all of the thread specific data in THREAD. + THREAD must be the calling thread. */ +extern void __pthread_destroy_specific (struct __pthread *thread); + + +/* Initialize newly create thread *THREAD's signal state data + structures. */ +extern error_t __pthread_sigstate_init (struct __pthread *thread); + +/* Destroy the signal state data structures associcated with thread + *THREAD. */ +extern void __pthread_sigstate_destroy (struct __pthread *thread); + +/* Modify thread *THREAD's signal state. */ +extern error_t __pthread_sigstate (struct __pthread *__restrict thread, int how, + const sigset_t *__restrict set, + sigset_t *__restrict oset, + int clear_pending); + + +/* Default thread attributes. */ +extern const struct __pthread_attr __pthread_default_attr; + +/* Default barrier attributes. */ +extern const struct __pthread_barrierattr __pthread_default_barrierattr; + +/* Default mutex attributes. */ +extern const struct __pthread_mutexattr __pthread_default_mutexattr; + +/* Default rdlock attributes. */ +extern const struct __pthread_rwlockattr __pthread_default_rwlockattr; + +/* Default condition attributes. */ +extern const struct __pthread_condattr __pthread_default_condattr; + +#endif /* pt-internal.h */ diff --git a/htl/pt-join.c b/htl/pt-join.c new file mode 100644 index 0000000000..329163d514 --- /dev/null +++ b/htl/pt-join.c @@ -0,0 +1,75 @@ +/* Wait for thread termination. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include + +#include + +/* Make calling thread wait for termination of thread THREAD. Return + the exit status of the thread in *STATUS. */ +int +pthread_join (pthread_t thread, void **status) +{ + struct __pthread *pthread; + int err = 0; + + /* Lookup the thread structure for THREAD. */ + pthread = __pthread_getid (thread); + if (pthread == NULL) + return ESRCH; + + __pthread_mutex_lock (&pthread->state_lock); + pthread_cleanup_push ((void (*)(void *)) __pthread_mutex_unlock, + &pthread->state_lock); + + /* Rely on pthread_cond_wait being a cancellation point to make + pthread_join one too. */ + while (pthread->state == PTHREAD_JOINABLE) + __pthread_cond_wait (&pthread->state_cond, &pthread->state_lock); + + pthread_cleanup_pop (0); + + switch (pthread->state) + { + case PTHREAD_EXITED: + /* THREAD has already exited. Salvage its exit status. */ + if (status != NULL) + *status = pthread->status; + + __pthread_mutex_unlock (&pthread->state_lock); + + __pthread_dealloc (pthread); + break; + + case PTHREAD_TERMINATED: + /* Pretend THREAD wasn't there in the first place. */ + __pthread_mutex_unlock (&pthread->state_lock); + err = ESRCH; + break; + + default: + /* Thou shalt not join non-joinable threads! */ + __pthread_mutex_unlock (&pthread->state_lock); + err = EINVAL; + break; + } + + return err; +} diff --git a/htl/pt-self.c b/htl/pt-self.c new file mode 100644 index 0000000000..0f932ac1f4 --- /dev/null +++ b/htl/pt-self.c @@ -0,0 +1,33 @@ +/* Get calling thread's ID. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +#include + +/* Return the thread ID of the calling thread. */ +pthread_t +__pthread_self (void) +{ + struct __pthread *self = _pthread_self (); + assert (self != NULL); + + return self->thread; +} + +strong_alias (__pthread_self, pthread_self); diff --git a/htl/pt-setcancelstate.c b/htl/pt-setcancelstate.c new file mode 100644 index 0000000000..de5c6880e6 --- /dev/null +++ b/htl/pt-setcancelstate.c @@ -0,0 +1,46 @@ +/* Set the cancel state for the calling thread. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +#include + +int +__pthread_setcancelstate (int state, int *oldstate) +{ + struct __pthread *p = _pthread_self (); + + switch (state) + { + default: + return EINVAL; + case PTHREAD_CANCEL_ENABLE: + case PTHREAD_CANCEL_DISABLE: + break; + } + + __pthread_mutex_lock (&p->cancel_lock); + if (oldstate != NULL) + *oldstate = p->cancel_state; + p->cancel_state = state; + __pthread_mutex_unlock (&p->cancel_lock); + + return 0; +} + +strong_alias (__pthread_setcancelstate, pthread_setcancelstate); diff --git a/htl/pt-setcanceltype.c b/htl/pt-setcanceltype.c new file mode 100644 index 0000000000..0f29a43a9a --- /dev/null +++ b/htl/pt-setcanceltype.c @@ -0,0 +1,46 @@ +/* Set the cancel type for the calling thread. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +#include + +int +__pthread_setcanceltype (int type, int *oldtype) +{ + struct __pthread *p = _pthread_self (); + + switch (type) + { + default: + return EINVAL; + case PTHREAD_CANCEL_DEFERRED: + case PTHREAD_CANCEL_ASYNCHRONOUS: + break; + } + + __pthread_mutex_lock (&p->cancel_lock); + if (oldtype != NULL) + *oldtype = p->cancel_type; + p->cancel_type = type; + __pthread_mutex_unlock (&p->cancel_lock); + + return 0; +} + +strong_alias (__pthread_setcanceltype, pthread_setcanceltype); diff --git a/htl/pt-sigmask.c b/htl/pt-sigmask.c new file mode 100644 index 0000000000..f55c508dfb --- /dev/null +++ b/htl/pt-sigmask.c @@ -0,0 +1,31 @@ +/* Get or set a thread's signal mask. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include + +#include + +int +pthread_sigmask (int how, const sigset_t *set, sigset_t *oset) +{ + struct __pthread *self = _pthread_self (); + + /* Do not clear SELF's pending signals. */ + return __pthread_sigstate (self, how, set, oset, 0); +} diff --git a/htl/pt-spin-inlines.c b/htl/pt-spin-inlines.c new file mode 100644 index 0000000000..379723524e --- /dev/null +++ b/htl/pt-spin-inlines.c @@ -0,0 +1,33 @@ +/* Spin locks non-inline functions. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +/* declares some extern inline functions. These + functions are declared additionally here for use when inlining is + not possible. */ + +#define _FORCE_INLINES +#define __PT_SPIN_INLINE /* empty */ + +#include + +/* Weak aliases for the spin lock functions. */ +weak_alias (__pthread_spin_destroy, pthread_spin_destroy); +weak_alias (__pthread_spin_init, pthread_spin_init); +weak_alias (__pthread_spin_trylock, pthread_spin_trylock); +weak_alias (__pthread_spin_lock, pthread_spin_lock); +weak_alias (__pthread_spin_unlock, pthread_spin_unlock); diff --git a/htl/pt-testcancel.c b/htl/pt-testcancel.c new file mode 100644 index 0000000000..783a6a6001 --- /dev/null +++ b/htl/pt-testcancel.c @@ -0,0 +1,35 @@ +/* Add an explicit cancelation point. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include + +#include + +void +pthread_testcancel (void) +{ + struct __pthread *p = _pthread_self (); + int cancelled; + + __pthread_mutex_lock (&p->cancel_lock); + cancelled = (p->cancel_state == PTHREAD_CANCEL_ENABLE) && p->cancel_pending; + __pthread_mutex_unlock (&p->cancel_lock); + + if (cancelled) + pthread_exit (PTHREAD_CANCELED); +} diff --git a/htl/pt-yield.c b/htl/pt-yield.c new file mode 100644 index 0000000000..0dee959b87 --- /dev/null +++ b/htl/pt-yield.c @@ -0,0 +1,26 @@ +/* Yield the processor to another thread or process. + Copyright (C) 2010-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include + +int +pthread_yield (void) +{ + return sched_yield (); +} diff --git a/htl/shlib-versions b/htl/shlib-versions new file mode 100644 index 0000000000..98e07a6c33 --- /dev/null +++ b/htl/shlib-versions @@ -0,0 +1 @@ +libpthread=0.3 diff --git a/htl/tests/Makefile b/htl/tests/Makefile new file mode 100644 index 0000000000..7177ad181e --- /dev/null +++ b/htl/tests/Makefile @@ -0,0 +1,40 @@ +ifdef INSTALL_ROOT +INSTALL_ROOT_CPPFLAGS = -isystem $(INSTALL_ROOT)/include +INSTALL_ROOT_LDFLAGS = -L$(INSTALL_ROOT)/lib -Wl,-rpath,$(INSTALL_ROOT)/lib +endif + +CFLAGS=-Wall -g + +LDLIBS = -lpthread + +CHECK_SRC := test-1.c test-2.c test-3.c test-6.c test-7.c test-8.c \ + test-9.c test-10.c test-11.c test-12.c test-13.c test-14.c \ + test-15.c test-16.c test-17.c test-__pthread_destroy_specific-skip.c + +CHECK_OBJS := $(addsuffix .o,$(basename $(notdir $(CHECK_SRC)))) +CHECK_PROGS := $(basename $(notdir $(CHECK_SRC))) \ + $(addsuffix -static, $(basename $(CHECK_SRC))) + +%.o: %.c + $(CC) $(INSTALL_ROOT_CPPFLAGS) $(CPPFLAGS) $(CFLAGS) $< -c -o $@ + +%: %.o + $(CC) $(INSTALL_ROOT_LDFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS) + +%-static: %.o + $(CC) -static $(INSTALL_ROOT_LDFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS) + +check: $(CHECK_OBJS) $(CHECK_PROGS) + for i in $(CHECK_PROGS); do \ + echo -n Running $$i...\ ; \ + if ./$$i 2>&1 > $$i.out; \ + then \ + echo Success.; \ + else \ + echo Failure.; \ + fi \ + done + +clean: + rm -f $(CHECK_OBJS) $(CHECK_PROGS) \ + $(addsuffix .out,$(basename $(notdir $(CHECK_PROGS)))) \ No newline at end of file diff --git a/htl/tests/README b/htl/tests/README new file mode 100644 index 0000000000..230f1b24f0 --- /dev/null +++ b/htl/tests/README @@ -0,0 +1,6 @@ +Testing of installed package: + + $ [libpthread]/configure --prefix=[install_root] + $ make + $ make install + $ make -C [libpthread]/tests/ INSTALL_ROOT=[install_root] clean check diff --git a/htl/tests/test-1.c b/htl/tests/test-1.c new file mode 100644 index 0000000000..25263ee2f2 --- /dev/null +++ b/htl/tests/test-1.c @@ -0,0 +1,68 @@ +/* Test mutexes. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#define THREADS 500 + +void * +foo (void *arg) +{ + pthread_mutex_t *mutex = arg; + pthread_mutex_lock (mutex); + pthread_mutex_unlock (mutex); + return mutex; +} + +int +main (int argc, char **argv) +{ + int i; + error_t err; + pthread_t tid[THREADS]; + pthread_mutex_t mutex[THREADS]; + + for (i = 0; i < THREADS; i++) + { + pthread_mutex_init (&mutex[i], 0); + pthread_mutex_lock (&mutex[i]); + err = pthread_create (&tid[i], 0, foo, &mutex[i]); + if (err) + error (1, err, "pthread_create"); + sched_yield (); + } + + for (i = THREADS - 1; i >= 0; i--) + { + void *ret; + pthread_mutex_unlock (&mutex[i]); + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + assert (ret == &mutex[i]); + } + + return 0; +} diff --git a/htl/tests/test-10.c b/htl/tests/test-10.c new file mode 100644 index 0000000000..31d3449d04 --- /dev/null +++ b/htl/tests/test-10.c @@ -0,0 +1,62 @@ +/* Test error checking mutexes. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + error_t err; + pthread_mutexattr_t mattr; + pthread_mutex_t mutex; + + err = pthread_mutexattr_init (&mattr); + if (err) + error (1, err, "pthread_mutexattr_init"); + + err = pthread_mutexattr_settype (&mattr, PTHREAD_MUTEX_ERRORCHECK); + if (err) + error (1, err, "pthread_mutexattr_settype"); + + err = pthread_mutex_init (&mutex, &mattr); + if (err) + error (1, err, "pthread_mutex_init"); + + err = pthread_mutexattr_destroy (&mattr); + if (err) + error (1, err, "pthread_mutexattr_destroy"); + + err = pthread_mutex_lock (&mutex); + assert (err == 0); + + err = pthread_mutex_lock (&mutex); + assert (err == EDEADLK); + + err = pthread_mutex_unlock (&mutex); + assert (err == 0); + + err = pthread_mutex_unlock (&mutex); + assert (err == EPERM); + + return 0; +} diff --git a/htl/tests/test-11.c b/htl/tests/test-11.c new file mode 100644 index 0000000000..f8c7a427e8 --- /dev/null +++ b/htl/tests/test-11.c @@ -0,0 +1,159 @@ +/* Test rwlocks. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#define THREADS 1 + +int a; +int b; + +/* Get a read lock and assert that a == b. */ +void * +test1 (void *arg) +{ + error_t err; + pthread_rwlock_t *lock = arg; + int i; + + for (i = 0; i < 200; i++) + { + err = pthread_rwlock_rdlock (lock); + assert (err == 0); + + assert (a == b); + + sched_yield (); + + assert (a == b); + + err = pthread_rwlock_unlock (lock); + assert (err == 0); + } + + return 0; +} + +int +main (int argc, char **argv) +{ + error_t err; + pthread_rwlockattr_t attr; + pthread_rwlock_t lock; + int pshared; + + int i; + pthread_t tid[THREADS]; + void *ret; + + err = pthread_rwlockattr_init (&attr); + if (err) + error (1, err, "pthread_rwlockattr_init"); + + err = pthread_rwlockattr_getpshared (&attr, &pshared); + if (err) + error (1, err, "pthread_rwlockattr_getpshared"); + + /* Assert the default state as mandated by POSIX. */ + assert (pshared == PTHREAD_PROCESS_PRIVATE); + + err = pthread_rwlockattr_setpshared (&attr, pshared); + if (err) + error (1, err, "pthread_rwlockattr_setpshared"); + + err = pthread_rwlock_init (&lock, &attr); + if (err) + error (1, err, "pthread_rwlock_init"); + + err = pthread_rwlockattr_destroy (&attr); + if (err) + error (1, err, "pthread_rwlockattr_destroy"); + + /* Now test the lock. */ + + for (i = 0; i < THREADS; i++) + { + err = pthread_create (&tid[i], 0, test1, &lock); + if (err) + error (1, err, "pthread_create"); + } + + for (i = 0; i < 10; i++) + { + sched_yield (); + + /* Get a write lock. */ + pthread_rwlock_wrlock (&lock); + /* Increment a and b giving other threads a chance to run in + between. */ + sched_yield (); + a++; + sched_yield (); + b++; + sched_yield (); + /* Unlock. */ + pthread_rwlock_unlock (&lock); + } + + for (i = 0; i < THREADS; i++) + { + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + } + + /* Read lock it. */ + err = pthread_rwlock_tryrdlock (&lock); + assert (err == 0); + + /* Try to write lock it. It should fail with EBUSY. */ + err = pthread_rwlock_trywrlock (&lock); + assert (err == EBUSY); + + /* Drop the read lock. */ + err = pthread_rwlock_unlock (&lock); + assert (err == 0); + + /* Get a write lock. */ + err = pthread_rwlock_trywrlock (&lock); + assert (err == 0); + + /* Fail trying to acquire another write lock. */ + err = pthread_rwlock_trywrlock (&lock); + assert (err == EBUSY); + + /* Try to get a read lock which should also fail. */ + err = pthread_rwlock_tryrdlock (&lock); + assert (err == EBUSY); + + /* Unlock it. */ + err = pthread_rwlock_unlock (&lock); + assert (err == 0); + + + err = pthread_rwlock_destroy (&lock); + if (err) + error (1, err, "pthread_rwlock_destroy"); + + return 0; +} diff --git a/htl/tests/test-12.c b/htl/tests/test-12.c new file mode 100644 index 0000000000..9676446182 --- /dev/null +++ b/htl/tests/test-12.c @@ -0,0 +1,45 @@ +/* Test concurrency level. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + int i; + int err; + + i = pthread_getconcurrency (); + assert (i == 0); + + err = pthread_setconcurrency (-1); + assert (err == EINVAL); + + err = pthread_setconcurrency (4); + assert (err == 0); + + i = pthread_getconcurrency (); + assert (i == 4); + + return 0; +} diff --git a/htl/tests/test-13.c b/htl/tests/test-13.c new file mode 100644 index 0000000000..d14214981e --- /dev/null +++ b/htl/tests/test-13.c @@ -0,0 +1,82 @@ +/* Test condition attributes and pthread_cond_timedwait. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + error_t err; + int i; + pthread_condattr_t attr; + pthread_cond_t cond; + struct timespec ts; + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + struct timeval before, after; + int diff; + + err = pthread_condattr_init (&attr); + if (err) + error (1, err, "pthread_condattr_init"); + + err = pthread_condattr_getpshared (&attr, &i); + if (err) + error (1, err, "pthread_condattr_getpshared"); + assert (i == PTHREAD_PROCESS_PRIVATE); + + err = pthread_condattr_setpshared (&attr, PTHREAD_PROCESS_PRIVATE); + assert (err == 0); + + err = pthread_cond_init (&cond, &attr); + if (err) + error (1, err, "pthread_cond_init"); + + err = pthread_condattr_destroy (&attr); + if (err) + error (1, err, "pthread_condattr_destroy"); + + gettimeofday (&before, 0); + ts.tv_sec = before.tv_sec + 1; + ts.tv_nsec = before.tv_usec * 1000; + + printf ("Starting wait @ %d\n", (int) before.tv_sec); + + pthread_mutex_lock (&m); + err = pthread_cond_timedwait (&cond, &m, &ts); + + gettimeofday (&after, 0); + + printf ("End wait @ %d (err = %d)\n", (int) after.tv_sec, err); + + assert (err == ETIMEDOUT); + + diff = after.tv_sec * 1000000 + after.tv_usec + - before.tv_sec * 1000000 - before.tv_usec; + + if (diff < 900000 || diff > 1100000) + error (1, EGRATUITOUS, "pthread_cond_timedwait waited %d us", diff); + + return 0; +} diff --git a/htl/tests/test-14.c b/htl/tests/test-14.c new file mode 100644 index 0000000000..6e7cef12fe --- /dev/null +++ b/htl/tests/test-14.c @@ -0,0 +1,60 @@ +/* Test pthread_mutex_timedlock. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + error_t err; + struct timespec ts; + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + struct timeval before, after; + int diff; + + gettimeofday (&before, 0); + ts.tv_sec = before.tv_sec + 1; + ts.tv_nsec = before.tv_usec * 1000; + + printf ("Starting wait @ %d\n", (int) before.tv_sec); + + pthread_mutex_lock (&m); + /* A default mutex shall dead lock if locked twice. As such we do + not need spawn a second thread. */ + err = pthread_mutex_timedlock (&m, &ts); + assert (err == ETIMEDOUT); + + gettimeofday (&after, 0); + + printf ("End wait @ %d\n", (int) after.tv_sec); + + diff = after.tv_sec * 1000000 + after.tv_usec + - before.tv_sec * 1000000 - before.tv_usec; + + if (diff < 900000 || diff > 1100000) + error (1, EGRATUITOUS, "pthread_mutex_timedlock waited %d us", diff); + + return 0; +} diff --git a/htl/tests/test-15.c b/htl/tests/test-15.c new file mode 100644 index 0000000000..baf866aae4 --- /dev/null +++ b/htl/tests/test-15.c @@ -0,0 +1,102 @@ +/* Test pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#define THREADS 10 + +pthread_rwlock_t rwlock; + +void * +test (void *arg) +{ + error_t err; + int foo = (int) arg; + struct timespec ts; + struct timeval before, after; + int diff; + + gettimeofday (&before, 0); + ts.tv_sec = before.tv_sec + 1; + ts.tv_nsec = before.tv_usec * 1000; + + printf ("Thread %d starting wait @ %d\n", pthread_self (), + (int) before.tv_sec); + + if (foo % 2 == 0) + err = pthread_rwlock_timedrdlock (&rwlock, &ts); + else + err = pthread_rwlock_timedwrlock (&rwlock, &ts); + + assert (err == ETIMEDOUT); + + gettimeofday (&after, 0); + + printf ("Thread %d ending wait @ %d\n", pthread_self (), (int) after.tv_sec); + + diff = after.tv_sec * 1000000 + after.tv_usec + - before.tv_sec * 1000000 - before.tv_usec; + + if (diff < 900000 || diff > 1100000) + error (1, EGRATUITOUS, "pthread_mutex_timedlock waited %d us", diff); + + return 0; +} + +int +main (int argc, char **argv) +{ + error_t err; + int i; + pthread_t tid[THREADS]; + + err = pthread_rwlock_init (&rwlock, 0); + if (err) + error (1, err, "pthread_rwlock_init"); + + /* Lock it so all the threads will block. */ + err = pthread_rwlock_wrlock (&rwlock); + assert (err == 0); + + for (i = 0; i < THREADS; i++) + { + err = pthread_create (&tid[i], 0, test, (void *) i); + if (err) + error (1, err, "pthread_create"); + } + + for (i = 0; i < THREADS; i++) + { + void *ret; + + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + + assert (ret == 0); + } + + return 0; +} diff --git a/htl/tests/test-16.c b/htl/tests/test-16.c new file mode 100644 index 0000000000..519aa84547 --- /dev/null +++ b/htl/tests/test-16.c @@ -0,0 +1,87 @@ +/* Test pthread_kill.c. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +pthread_t testthread; + +int i; + +void * +test (void *arg) +{ + error_t err; + + printf ("test: %d\n", pthread_self ()); + + err = pthread_kill (pthread_self (), SIGINFO); + if (err) + error (1, err, "pthread_kill"); + + /* To avoid using condition variables in a signal handler. */ + while (i == 0) + sched_yield (); + + return 0; +} + +static void +handler (int sig) +{ + assert (pthread_equal (pthread_self (), testthread)); + printf ("handler: %d\n", pthread_self ()); + i = 1; +} + +int +main (int argc, char **argv) +{ + error_t err; + struct sigaction sa; + void *ret; + + printf ("main: %d\n", pthread_self ()); + + sa.sa_handler = handler; + sa.sa_mask = 0; + sa.sa_flags = 0; + + err = sigaction (SIGINFO, &sa, 0); + if (err) + error (1, err, "sigaction"); + + err = pthread_create (&testthread, 0, test, 0); + if (err) + error (1, err, "pthread_create"); + + err = pthread_join (testthread, &ret); + if (err) + error (1, err, "pthread_join"); + + assert (ret == 0); + + return 0; +} diff --git a/htl/tests/test-17.c b/htl/tests/test-17.c new file mode 100644 index 0000000000..ffc90b5f74 --- /dev/null +++ b/htl/tests/test-17.c @@ -0,0 +1,73 @@ +/* Test that the key reuse inside libpthread does not cause thread + specific values to persist. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include + +void +work (int iter) +{ + error_t err; + pthread_key_t key1; + pthread_key_t key2; + void *value1; + void *value2; + + printf ("work/%d: start\n", iter); + err = pthread_key_create (&key1, NULL); + assert (err == 0); + err = pthread_key_create (&key2, NULL); + assert (err == 0); + + value1 = pthread_getspecific (key1); + value2 = pthread_getspecific (key2); + printf ("work/%d: pre-setspecific: %p,%p\n", iter, value1, value2); + assert (value1 == NULL); + assert (value2 == NULL); + err = pthread_setspecific (key1, (void *) (0x100 + iter)); + assert (err == 0); + err = pthread_setspecific (key2, (void *) (0x200 + iter)); + assert (err == 0); + + value1 = pthread_getspecific (key1); + value2 = pthread_getspecific (key2); + printf ("work/%d: post-setspecific: %p,%p\n", iter, value1, value2); + assert (value1 == (void *) (0x100 + iter)); + assert (value2 == (void *) (0x200 + iter)); + + err = pthread_key_delete (key1); + assert (err == 0); + err = pthread_key_delete (key2); + assert (err == 0); +} + +int +main (int argc, char *argv[]) +{ + int i; + + for (i = 0; i < 8; ++i) + work (i + 1); + + return 0; +} diff --git a/htl/tests/test-2.c b/htl/tests/test-2.c new file mode 100644 index 0000000000..1194a3427a --- /dev/null +++ b/htl/tests/test-2.c @@ -0,0 +1,56 @@ +/* Test detachability. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +void * +thread (void *arg) +{ + while (1) + sched_yield (); +} + +int +main (int argc, char **argv) +{ + int err; + pthread_t tid; + void *ret; + + err = pthread_create (&tid, 0, thread, 0); + if (err) + error (1, err, "pthread_create"); + + err = pthread_detach (tid); + if (err) + error (1, err, "pthread_detach"); + + err = pthread_detach (tid); + assert (err == EINVAL); + + err = pthread_join (tid, &ret); + assert (err == EINVAL); + + return 0; +} diff --git a/htl/tests/test-3.c b/htl/tests/test-3.c new file mode 100644 index 0000000000..beed473d3c --- /dev/null +++ b/htl/tests/test-3.c @@ -0,0 +1,71 @@ +/* Test the thread attribute get and set methods. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + error_t err; + pthread_attr_t attr; + + int i; + struct sched_param sp; + void *p; + size_t sz; + + err = pthread_attr_init (&attr); + assert_perror (err); + + err = pthread_attr_destroy (&attr); + assert_perror (err); + + err = pthread_attr_init (&attr); + assert_perror (err); + +#define TEST1(foo, rv, v) \ + err = pthread_attr_get##foo (&attr, rv); \ + assert_perror (err); \ + \ + err = pthread_attr_set##foo (&attr, v); \ + assert_perror (err); + +#define TEST(foo, rv, v) TEST1(foo, rv, v) + + TEST (inheritsched, &i, i); + TEST (schedparam, &sp, &sp); + TEST (schedpolicy, &i, i); + TEST (scope, &i, i); + TEST (stackaddr, &p, p); + TEST (detachstate, &i, i); + TEST (guardsize, &sz, sz); + TEST (stacksize, &sz, sz); + + err = pthread_attr_getstack (&attr, &p, &sz); + assert_perror (err); + + err = pthread_attr_setstack (&attr, p, sz); + assert_perror (err); + + return 0; +} diff --git a/htl/tests/test-4.c b/htl/tests/test-4.c new file mode 100644 index 0000000000..b8c24b78f1 --- /dev/null +++ b/htl/tests/test-4.c @@ -0,0 +1,102 @@ +/* Test the stack guard. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +size_t stacksize; + +void * +thr (void *arg) +{ + int i; + char *foo; + + foo = alloca (3 * stacksize / 4); + for (i = 0; i < sizeof foo; i++) + foo[i] = -1; + + return (void *) 1; +} + +int +main (int argc, char *argv[]) +{ + error_t err; + pid_t child; + + child = fork (); + switch (child) + { + case -1: + error (1, errno, "fork"); + break; + + case 0: + { + pthread_attr_t attr; + pthread_t tid; + void *ret; + + err = pthread_attr_init (&attr); + assert_perror (err); + + err = pthread_attr_getstacksize (&attr, &stacksize); + assert_perror (err); + + err = pthread_attr_setguardsize (&attr, stacksize / 2); + if (err == ENOTSUP) + { + printf ("Stack guard attribute not supported.\n"); + return 1; + } + assert_perror (err); + + err = pthread_create (&tid, &attr, thr, 0); + assert_perror (err); + + err = pthread_attr_destroy (&attr); + assert_perror (err); + + err = pthread_join (tid, &ret); + /* Should never be successful. */ + printf ("Thread did not segfault!?!\n"); + assert_perror (err); + return 0; + } + + default: + { + pid_t pid; + int status; + + pid = waitpid (child, &status, 0); + printf ("pid = %d; child = %d; status = %d\n", pid, child, status); + assert (pid == child); + assert (status != 0); + } + } + + return 0; +} diff --git a/htl/tests/test-5.c b/htl/tests/test-5.c new file mode 100644 index 0000000000..ef9691c869 --- /dev/null +++ b/htl/tests/test-5.c @@ -0,0 +1,91 @@ +/* Test signals. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +void * +thr (void *arg) +{ + *(int *) 0 = 0; + return 0; +} + +int foobar; + +int +main (int argc, char *argv[]) +{ + error_t err; + pid_t child; + + struct rlimit limit; + + limit.rlim_cur = 0; + limit.rlim_max = 0; + + err = setrlimit (RLIMIT_CORE, &limit); + if (err) + error (1, err, "setrlimit"); + + child = fork (); + switch (child) + { + case -1: + error (1, errno, "fork"); + break; + + case 0: + { + pthread_t tid; + void *ret; + + err = pthread_create (&tid, 0, thr, 0); + if (err) + error (1, err, "pthread_create"); + + err = pthread_join (tid, &ret); + assert_perror (err); + + /* Should have never returned. Our parent expects us to fail + thus we succeed and indicate the error. */ + return 0; + } + + default: + { + pid_t pid; + int status; + + pid = waitpid (child, &status, 0); + printf ("pid = %d; child = %d; status = %d\n", pid, child, status); + assert (pid == child); + assert (status != 0); + } + } + + return 0; +} diff --git a/htl/tests/test-6.c b/htl/tests/test-6.c new file mode 100644 index 0000000000..e25d419e6f --- /dev/null +++ b/htl/tests/test-6.c @@ -0,0 +1,114 @@ +/* Test barriers. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#define THREADS 500 +#define WAITS 3 + +void * +dowait (void *arg) +{ + pthread_barrier_t *barrier = arg; + int ret; + + ret = pthread_barrier_wait (barrier); + printf ("%d ", pthread_self ()); + return (void *) ret; +} + +int +main (int argc, char **argv) +{ + pthread_barrierattr_t attr; + pthread_barrier_t barrier; + + int i, j; + error_t err; + pthread_t tid[THREADS]; + + int havesyncs; + + err = pthread_barrierattr_init (&attr); + if (err) + error (1, err, "pthread_barrierattr_init"); + + err = pthread_barrierattr_getpshared (&attr, &i); + if (err) + error (1, err, "pthread_barrierattr_getpshared"); + assert (i == PTHREAD_PROCESS_PRIVATE || i == PTHREAD_PROCESS_SHARED); + + err = pthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_PRIVATE); + if (err) + error (1, err, "pthread_barrierattr_setpshared"); + + err = pthread_barrier_init (&barrier, &attr, THREADS + 1); + if (err) + error (1, err, "pthread_barrier_init"); + + for (j = 0; j < WAITS; j++) + { + + for (i = 0; i < THREADS; i++) + { + err = pthread_create (&tid[i], 0, dowait, &barrier); + if (err) + error (1, err, "pthread_create (%d)", i); + } + + printf ("Manager will now call pthread_barrier_wait.\n"); + + havesyncs + = pthread_barrier_wait (&barrier) == PTHREAD_BARRIER_SERIAL_THREAD + ? 1 : 0; + + for (i = THREADS - 1; i >= 0; i--) + { + void *ret; + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + + switch ((int) ret) + { + case 0: + break; + + case PTHREAD_BARRIER_SERIAL_THREAD: + havesyncs++; + break; + + default: + assert (!"Unknown value returned from pthread_barrier_wait."); + break; + } + } + + printf ("\n"); + + assert (havesyncs == 1); + } + + return 0; +} diff --git a/htl/tests/test-7.c b/htl/tests/test-7.c new file mode 100644 index 0000000000..4823de2486 --- /dev/null +++ b/htl/tests/test-7.c @@ -0,0 +1,89 @@ +/* Test Thread-Specific Data. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#define THREADS 10 +#define KEYS 400 + +pthread_key_t key[KEYS]; + +void * +thr (void *arg) +{ + error_t err; + int i; + + for (i = 0; i < KEYS; i++) + { + printf ("pthread_getspecific(%d).\n", key[i]); + assert (pthread_getspecific (key[i]) == NULL); + printf ("pthread_setspecific(%d, %d).\n", key[i], pthread_self ()); + err = pthread_setspecific (key[i], (void *) pthread_self ()); + printf ("pthread_setspecific(%d, %d) => %d.\n", key[i], pthread_self (), + err); + assert_perror (err); + } + + return 0; +} + +int +main (int argc, char **argv) +{ + error_t err; + int i; + pthread_t tid[THREADS]; + + void des (void *val) + { + assert ((pthread_t) val == pthread_self ()); + } + + assert (pthread_getspecific ((pthread_key_t) 0) == NULL); + assert (pthread_setspecific ((pthread_key_t) 0, (void *) 0x1) == EINVAL); + + for (i = 0; i < KEYS; i++) + err = pthread_key_create (&key[i], des); + + for (i = 0; i < THREADS; i++) + { + err = pthread_create (&tid[i], 0, thr, 0); + if (err) + error (1, err, "pthread_create (%d)", i); + } + + for (i = 0; i < THREADS; i++) + { + void *ret; + + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + + assert (ret == 0); + } + + return 0; +} diff --git a/htl/tests/test-8.c b/htl/tests/test-8.c new file mode 100644 index 0000000000..9cf74a70c4 --- /dev/null +++ b/htl/tests/test-8.c @@ -0,0 +1,78 @@ +/* Test pthread_once. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#define THREADS 10 + +pthread_once_t inc_var_once = PTHREAD_ONCE_INIT; +int var; + +void +inc_var (void) +{ + var++; +} + +void * +thr (void *arg) +{ + int i; + + for (i = 0; i < 500; i++) + pthread_once (&inc_var_once, inc_var); + + return 0; +} + +int +main (int argc, char **argv) +{ + error_t err; + int i; + pthread_t tid[THREADS]; + + for (i = 0; i < THREADS; i++) + { + err = pthread_create (&tid[i], 0, thr, 0); + if (err) + error (1, err, "pthread_create (%d)", i); + } + + assert (thr (0) == 0); + + for (i = 0; i < THREADS; i++) + { + void *ret; + + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + + assert (ret == 0); + } + + assert (var == 1); + + return 0; +} diff --git a/htl/tests/test-9.c b/htl/tests/test-9.c new file mode 100644 index 0000000000..ad6bc36de5 --- /dev/null +++ b/htl/tests/test-9.c @@ -0,0 +1,104 @@ +/* Test recursive mutexes. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#define THREADS 10 + +int foo; + +void * +thr (void *arg) +{ + int i; + + pthread_mutex_lock (arg); + + foo = pthread_self (); + + for (i = 0; i < 500; i++) + pthread_mutex_lock (arg); + for (i = 0; i < 500; i++) + pthread_mutex_unlock (arg); + + assert (foo == pthread_self ()); + + pthread_mutex_unlock (arg); + + return 0; +} + +int +main (int argc, char **argv) +{ + error_t err; + int i; + pthread_t tid[THREADS]; + pthread_mutexattr_t mattr; + pthread_mutex_t mutex; + + err = pthread_mutexattr_init (&mattr); + if (err) + error (1, err, "pthread_mutexattr_init"); + + err = pthread_mutexattr_settype (&mattr, PTHREAD_MUTEX_RECURSIVE); + if (err) + error (1, err, "pthread_mutexattr_settype"); + + err = pthread_mutex_init (&mutex, &mattr); + if (err) + error (1, err, "pthread_mutex_init"); + + err = pthread_mutexattr_destroy (&mattr); + if (err) + error (1, err, "pthread_mutexattr_destroy"); + + pthread_mutex_lock (&mutex); + pthread_mutex_lock (&mutex); + pthread_mutex_unlock (&mutex); + pthread_mutex_unlock (&mutex); + + for (i = 0; i < THREADS; i++) + { + err = pthread_create (&tid[i], 0, thr, &mutex); + if (err) + error (1, err, "pthread_create (%d)", i); + } + + for (i = 0; i < THREADS; i++) + { + void *ret; + + err = pthread_join (tid[i], &ret); + if (err) + error (1, err, "pthread_join"); + + assert (ret == 0); + } + + err = pthread_mutex_destroy (&mutex); + if (err) + error (1, err, "pthread_mutex_destroy"); + + return 0; +} diff --git a/htl/tests/test-__pthread_destroy_specific-skip.c b/htl/tests/test-__pthread_destroy_specific-skip.c new file mode 100644 index 0000000000..c54ccad88d --- /dev/null +++ b/htl/tests/test-__pthread_destroy_specific-skip.c @@ -0,0 +1,100 @@ +/* Check that __pthread_destroy_specific works correctly if it has to skip + unused slots. + Copyright (C) 2000-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#define _GNU_SOURCE + +#include +#include +#include + + +#define N_k 42 + +static volatile int v; + +static void +d (void *x) +{ + int *i = (int *) x; + + if (v != *i) + error (1, 0, "FAILED %d %d", v, *i); + v += 2; + + printf ("%s %d\n", __FUNCTION__, *i); + fflush (stdout); +} + +static void * +test (void *x) +{ + pthread_key_t k[N_k]; + static int k_v[N_k]; + + int err, i; + + for (i = 0; i < N_k; i += 1) + { + err = pthread_key_create (&k[i], &d); + if (err != 0) + error (1, err, "pthread_key_create %d", i); + } + + for (i = 0; i < N_k; i += 1) + { + k_v[i] = i; + err = pthread_setspecific (k[i], &k_v[i]); + if (err != 0) + error (1, err, "pthread_setspecific %d", i); + } + + /* Delete every even key. */ + for (i = 0; i < N_k; i += 2) + { + err = pthread_key_delete (k[i]); + if (err != 0) + error (1, err, "pthread_key_delete %d", i); + } + + v = 1; + pthread_exit (NULL); + + return NULL; +} + + +int +main (void) +{ + pthread_t tid; + int err; + + err = pthread_create (&tid, 0, test, NULL); + if (err != 0) + error (1, err, "pthread_create"); + + err = pthread_join (tid, NULL); + if (err) + error (1, err, "pthread_join"); + + if (v != N_k + 1) + error (1, 0, "FAILED END %d %d", v, N_k + 1); + + return 0; +} -- cgit v1.2.3