diff options
author | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
commit | b137080f19736ee33fede2e88bb54438604cf86b (patch) | |
tree | 377ac0ac449528621eb192cd245adadb5fd53668 /lib/libthr | |
parent | ab21a29eb607d4dfe389b965fbdee27558e791aa (diff) | |
parent | 4a8d07956d121238d006d34ffe7d6269744e8b1a (diff) | |
download | FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.zip FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.tar.gz |
Merge from head@274682
Diffstat (limited to 'lib/libthr')
-rw-r--r-- | lib/libthr/Makefile | 2 | ||||
-rw-r--r-- | lib/libthr/Makefile.amd64 | 6 | ||||
-rw-r--r-- | lib/libthr/Makefile.i386 | 6 | ||||
-rw-r--r-- | lib/libthr/libthr.3 | 223 | ||||
-rw-r--r-- | lib/libthr/tests/Makefile | 58 | ||||
-rw-r--r-- | lib/libthr/tests/dlopen/Makefile | 30 | ||||
-rw-r--r-- | lib/libthr/tests/dlopen/dso/Makefile | 19 | ||||
-rw-r--r-- | lib/libthr/thread/thr_cond.c | 2 | ||||
-rw-r--r-- | lib/libthr/thread/thr_init.c | 11 | ||||
-rw-r--r-- | lib/libthr/thread/thr_stack.c | 7 |
10 files changed, 358 insertions, 6 deletions
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile index cfcc41e..5cbd0aa 100644 --- a/lib/libthr/Makefile +++ b/lib/libthr/Makefile @@ -64,4 +64,6 @@ SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a CFLAGS+=-DSYSCALL_COMPAT .endif +.include <bsd.arch.inc.mk> + .include <bsd.lib.mk> diff --git a/lib/libthr/Makefile.amd64 b/lib/libthr/Makefile.amd64 new file mode 100644 index 0000000..dd0f5b0 --- /dev/null +++ b/lib/libthr/Makefile.amd64 @@ -0,0 +1,6 @@ +# $FreeBSD$ + +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + diff --git a/lib/libthr/Makefile.i386 b/lib/libthr/Makefile.i386 new file mode 100644 index 0000000..dd0f5b0 --- /dev/null +++ b/lib/libthr/Makefile.i386 @@ -0,0 +1,6 @@ +# $FreeBSD$ + +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + diff --git a/lib/libthr/libthr.3 b/lib/libthr/libthr.3 index bfbebec..4b636ce 100644 --- a/lib/libthr/libthr.3 +++ b/lib/libthr/libthr.3 @@ -1,6 +1,11 @@ .\" Copyright (c) 2005 Robert N. M. Watson +.\" Copyright (c) 2014 The FreeBSD Foundation, Inc. .\" All rights reserved. .\" +.\" Part of this documentation was written by +.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship +.\" from the FreeBSD Foundation. +.\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -24,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 19, 2007 +.Dd September 26, 2014 .Dt LIBTHR 3 .Os .Sh NAME @@ -45,8 +50,222 @@ has been optimized for use by applications expecting system scope thread semantics, and can provide significant performance improvements compared to .Lb libkse . +.Pp +The library is tightly integrated with the run-time link editor +.Xr ld-elf.so.1 1 +and +.Lb libc ; +all three components must be built from the same source tree. +Mixing +.Li libc +and +.Nm +libraries from different versions of +.Fx +is not supported. +The run-time linker +.Xr ld-elf.so.1 1 +has some code to ensure backward-compatibility with older versions of +.Nm . +.Pp +The man page documents the quirks and tunables of the +.Nm . +When linking with +.Li -lpthread , +the run-time dependency +.Li libthr.so.3 +is recorded in the produced object. +.Sh MUTEX ACQUISITION +A locked mutex (see +.Xr pthread_mutex_lock 3 ) +is represented by a volatile variable of type +.Dv lwpid_t , +which records the global system identifier of the thread +owning the lock. +.Nm +performs a contested mutex acquisition in three stages, each of which +is more resource-consuming than the previous. +The first two stages are only applied for a mutex of +.Dv PTHREAD_MUTEX_ADAPTIVE_NP +type and +.Dv PTHREAD_PRIO_NONE +protocol (see +.Xr pthread_mutexattr 3 ) . +.Pp +First, on SMP systems, a spin loop +is performed, where the library attempts to acquire the lock by +.Xr atomic 9 +operations. +The loop count is controlled by the +.Ev LIBPTHREAD_SPINLOOPS +environment variable, with a default value of 2000. +.Pp +If the spin loop +was unable to acquire the mutex, a yield loop +is executed, performing the same +.Xr atomic 9 +acquisition attempts as the spin loop, +but each attempt is followed by a yield of the CPU time +of the thread using the +.Xr sched_yield 2 +syscall. +By default, the yield loop +is not executed. +This is controlled by the +.Ev LIBPTHREAD_YIELDLOOPS +environment variable. +.Pp +If both the spin and yield loops +failed to acquire the lock, the thread is taken off the CPU and +put to sleep in the kernel with the +.Xr umtx 2 +syscall. +The kernel wakes up a thread and hands the ownership of the lock to +the woken thread when the lock becomes available. +.Sh THREAD STACKS +Each thread is provided with a private user-mode stack area +used by the C runtime. +The size of the main (initial) thread stack is set by the kernel, and is +controlled by the +.Dv RLIMIT_STACK +process resource limit (see +.Xr getrlimit 2 ) . +.Pp +By default, the main thread's stack size is equal to the value of +.Dv RLIMIT_STACK +for the process. +If the +.Ev LIBPTHREAD_SPLITSTACK_MAIN +environment variable is present in the process environment +(its value does not matter), +the main thread's stack is reduced to 4MB on 64bit architectures, and to +2MB on 32bit architectures, when the threading library is initialized. +The rest of the address space area which has been reserved by the +kernel for the initial process stack is used for non-initial thread stacks +in this case. +The presence of the +.Ev LIBPTHREAD_BIGSTACK_MAIN +environment variable overrides +.Ev LIBPTHREAD_SPLITSTACK_MAIN ; +it is kept for backward-compatibility. +.Pp +The size of stacks for threads created by the process at run-time +with the +.Xr pthread_create 3 +call is controlled by thread attributes: see +.Xr pthread_attr 3 , +in particular, the +.Xr pthread_attr_setstacksize 3 , +.Xr pthread_attr_setguardsize 3 +and +.Xr pthread_attr_setstackaddr 3 +functions. +If no attributes for the thread stack size are specified, the default +non-initial thread stack size is 2MB for 64bit architectures, and 1MB +for 32bit architectures. +.Sh RUN-TIME SETTINGS +The following environment variables are recognized by +.Nm +and adjust the operation of the library at run-time: +.Bl -tag -width LIBPTHREAD_SPLITSTACK_MAIN +.It Ev LIBPTHREAD_BIGSTACK_MAIN +Disables the reduction of the initial thread stack enabled by +.Ev LIBPTHREAD_SPLITSTACK_MAIN . +.It Ev LIBPTHREAD_SPLITSTACK_MAIN +Causes a reduction of the initial thread stack, as described in the +section +.Sx THREAD STACKS . +This was the default behaviour of +.Nm +before +.Fx 11.0 . +.It Ev LIBPTHREAD_SPINLOOPS +The integer value of the variable overrides the default count of +iterations in the +.Li spin loop +of the mutex acquisition. +The default count is 2000, set by the +.Dv MUTEX_ADAPTIVE_SPINS +constant in the +.Nm +sources. +.It Ev LIBPTHREAD_YIELDLOOPS +A non-zero integer value enables the yield loop +in the process of the mutex acquisition. +The value is the count of loop operations. +.It Ev LIBPTHREAD_QUEUE_FIFO +The integer value of the variable specifies how often blocked +threads are inserted at the head of the sleep queue, instead of its tail. +Bigger values reduce the frequency of the FIFO discipline. +The value must be between 0 and 255. +.El +.Sh INTERACTION WITH RUN-TIME LINKER +The +.Nm +library must appear before +.Li libc +in the global order of depended objects. +.Pp +Loading +.Nm +with the +.Xr dlopen 3 +call in the process after the program binary is activated +is not supported, and causes miscellaneous and hard-to-diagnose misbehaviour. +This is due to +.Nm +interposing several important +.Li libc +symbols to provide thread-safe services. +In particular, +.Dv errno +and the locking stubs from +.Li libc +are affected. +This requirement is currently not enforced. +.Pp +If the program loads any modules at run-time, and those modules may require +threading services, the main program binary must be linked with +.Li libpthread , +even if it does not require any services from the library. +.Pp +.Nm +cannot be unloaded; the +.Xr dlclose 3 +function does not perform any action when called with a handle for +.Nm . +One of the reasons is that the interposing of +.Li libc +functions cannot be undone. +.Sh SIGNALS +The implementation also interposes the user-installed +.Xr signal 3 +handlers. +This interposing is done to postpone signal delivery to threads which +entered (libthr-internal) critical sections, where the calling +of the user-provided signal handler is unsafe. +An example of such a situation is owning the internal library lock. +When a signal is delivered while the signal handler cannot be safely +called, the call is postponed and performed until after the exit from +the critical section. +This should be taken into account when interpreting +.Xr ktrace 1 +logs. .Sh SEE ALSO -.Xr pthread 3 +.Xr ktrace 1 , +.Xr ld-elf.so.1 1 , +.Xr getrlimit 2 , +.Xr umtx 2 , +.Xr dlclose 3 , +.Xr dlopen 3 , +.Xr errno 3 , +.Xr getenv 3 , +.Xr libc 3 , +.Xr pthread_attr 3 , +.Xr pthread_attr_setstacksize 3 , +.Xr pthread_create 3 , +.Xr signal 3 , +.Xr atomic 9 .Sh AUTHORS .An -nosplit The diff --git a/lib/libthr/tests/Makefile b/lib/libthr/tests/Makefile new file mode 100644 index 0000000..50f07f0 --- /dev/null +++ b/lib/libthr/tests/Makefile @@ -0,0 +1,58 @@ +# $FreeBSD$ + +OBJTOP= ${.OBJDIR:H:H:H} +SRCTOP= ${.CURDIR:H:H:H} +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread + +TESTSDIR= ${TESTSBASE}/lib/libthr + +# TODO: t_name (missing pthread_getname_np support in FreeBSD) +NETBSD_ATF_TESTS_C= barrier_test +NETBSD_ATF_TESTS_C+= cond_test +NETBSD_ATF_TESTS_C+= condwait_test +NETBSD_ATF_TESTS_C+= detach_test +NETBSD_ATF_TESTS_C+= equal_test +NETBSD_ATF_TESTS_C+= fork_test +NETBSD_ATF_TESTS_C+= fpu_test +NETBSD_ATF_TESTS_C+= join_test +NETBSD_ATF_TESTS_C+= kill_test +NETBSD_ATF_TESTS_C+= mutex_test +NETBSD_ATF_TESTS_C+= once_test +NETBSD_ATF_TESTS_C+= preempt_test +NETBSD_ATF_TESTS_C+= rwlock_test +NETBSD_ATF_TESTS_C+= sem_test +NETBSD_ATF_TESTS_C+= sigmask_test +NETBSD_ATF_TESTS_C+= sigsuspend_test +NETBSD_ATF_TESTS_C+= siglongjmp_test +NETBSD_ATF_TESTS_C+= sleep_test +NETBSD_ATF_TESTS_C+= swapcontext_test + +NETBSD_ATF_TESTS_SH= atexit_test +NETBSD_ATF_TESTS_SH+= cancel_test +NETBSD_ATF_TESTS_SH+= exit_test +NETBSD_ATF_TESTS_SH+= resolv_test + +DPADD+= ${LIBPTHREAD} +LDADD+= -lpthread +DPADD.fpu_test+= ${LIBM} +LDADD.fpu_test+= -lm +DPADD.sem_test+= ${LIBRT} +LDADD.sem_test+= -lrt + +BINDIR= ${TESTSDIR} + +PROGS= h_atexit +PROGS+= h_cancel +PROGS+= h_exit +PROGS+= h_resolv + +FILESDIR= ${TESTSDIR} +FILES= d_mach + +TESTS_SUBDIRS= dlopen + +.include <netbsd-tests.test.mk> + +CFLAGS.condwait_test+= -I${SRCTOP}/contrib/netbsd-tests/lib/libc/gen + +.include <bsd.test.mk> diff --git a/lib/libthr/tests/dlopen/Makefile b/lib/libthr/tests/dlopen/Makefile new file mode 100644 index 0000000..0764bfa --- /dev/null +++ b/lib/libthr/tests/dlopen/Makefile @@ -0,0 +1,30 @@ +# $FreeBSD$ + +OBJTOP= ${.OBJDIR:H:H:H:H} +SRCTOP= ${.CURDIR:H:H:H:H} +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread/dlopen + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/lib/libthr/dlopen + +CFLAGS+= -DTESTDIR=\"${TESTSDIR:Q}/\" +LDFLAGS+= -L${.OBJDIR}/dso -Wl,-rpath=${TESTDIR} + +.if !defined(NO_PIC) +SUBDIR+= dso + +NETBSD_ATF_TESTS_C= dlopen_test +NETBSD_ATF_TESTS_C+= main_pthread_create_test +# XXX: this blocks running the testcase +#NETBSD_ATF_TESTS_C+= dso_pthread_create_test + +.for t in dlopen_test main_pthread_create_test +DPADD.$t+= ${LIBPTHREAD} +LDADD.$t+= -lpthread +.endfor +.endif + +.include <netbsd-tests.test.mk> + +.include <bsd.test.mk> diff --git a/lib/libthr/tests/dlopen/dso/Makefile b/lib/libthr/tests/dlopen/dso/Makefile new file mode 100644 index 0000000..080dec9 --- /dev/null +++ b/lib/libthr/tests/dlopen/dso/Makefile @@ -0,0 +1,19 @@ +# $FreeBSD$ + +OBJTOP= ${.OBJDIR:H:H:H:H:H} +SRCTOP= ${.CURDIR:H:H:H:H:H} +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread/dlopen/dso + +SHLIB= h_pthread_dlopen +SHLIB_MAJOR= 1 +SHLIB_NAME= h_pthread_dlopen.so.${SHLIB_MAJOR} +SRCS= h_pthread_dlopen.c + +DPADD+= ${LIBPTHREAD} +LDADD+= -lpthread + +LIBDIR= ${TESTSBASE}/lib/libthr/dlopen + +.include <netbsd-tests.test.mk> + +.include <bsd.lib.mk> diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c index 6af15db..71b4293 100644 --- a/lib/libthr/thread/thr_cond.c +++ b/lib/libthr/thread/thr_cond.c @@ -150,7 +150,7 @@ _pthread_cond_destroy(pthread_cond_t *cond) } /* - * Cancellation behaivor: + * Cancellation behavior: * Thread may be canceled at start, if thread is canceled, it means it * did not get a wakeup from pthread_cond_signal(), otherwise, it is * not canceled. diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 937d83f..6d6a532 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -37,6 +37,7 @@ #include <sys/types.h> #include <sys/signalvar.h> #include <sys/ioctl.h> +#include <sys/resource.h> #include <sys/sysctl.h> #include <sys/ttycom.h> #include <sys/mman.h> @@ -441,9 +442,10 @@ init_main_thread(struct pthread *thread) static void init_private(void) { + struct rlimit rlim; size_t len; int mib[2]; - char *env; + char *env, *env_bigstack, *env_splitstack; _thr_umutex_init(&_mutex_static_lock); _thr_umutex_init(&_cond_static_lock); @@ -471,6 +473,13 @@ init_private(void) len = sizeof (_usrstack); if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) PANIC("Cannot get kern.usrstack from sysctl"); + env_bigstack = getenv("LIBPTHREAD_BIGSTACK_MAIN"); + env_splitstack = getenv("LIBPTHREAD_SPLITSTACK_MAIN"); + if (env_bigstack != NULL || env_splitstack == NULL) { + if (getrlimit(RLIMIT_STACK, &rlim) == -1) + PANIC("Cannot get stack rlimit"); + _thr_stack_initial = rlim.rlim_cur; + } len = sizeof(_thr_is_smp); sysctlbyname("kern.smp.cpus", &_thr_is_smp, &len, NULL, 0); _thr_is_smp = (_thr_is_smp > 1); diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c index 15a9c82..e5d149e 100644 --- a/lib/libthr/thread/thr_stack.c +++ b/lib/libthr/thread/thr_stack.c @@ -246,7 +246,10 @@ _thr_stack_alloc(struct pthread_attr *attr) THREAD_LIST_UNLOCK(curthread); } else { - /* Allocate a stack from usrstack. */ + /* + * Allocate a stack from or below usrstack, depending + * on the LIBPTHREAD_BIGSTACK_MAIN env variable. + */ if (last_stack == NULL) last_stack = _usrstack - _thr_stack_initial - _thr_guard_default; @@ -268,7 +271,7 @@ _thr_stack_alloc(struct pthread_attr *attr) /* Map the stack and guard page together, and split guard page from allocated space: */ - if ((stackaddr = mmap(stackaddr, stacksize+guardsize, + if ((stackaddr = mmap(stackaddr, stacksize + guardsize, _rtld_get_stack_prot(), MAP_STACK, -1, 0)) != MAP_FAILED && (guardsize == 0 || |