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 o