diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2026-02-15 01:45:16 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2026-02-15 01:45:16 +0000 |
| commit | 56a7ce8416d181a2060d7a428aed9c3c6a431e6d (patch) | |
| tree | 102efa260400b2c1ef36733c53fbe2e6b747405c /lib/libpthread | |
| parent | a339cc353658ca6abbf6ad2919a9269210475b41 (diff) | |
Diffstat (limited to 'lib/libpthread')
| -rw-r--r-- | lib/libpthread/Makefile | 13 | ||||
| -rw-r--r-- | lib/libpthread/dlopen/t_dlopen.c | 133 | ||||
| -rw-r--r-- | lib/libpthread/dlopen/t_dso_pthread_create.c | 43 | ||||
| -rw-r--r-- | lib/libpthread/t_once.c | 78 |
4 files changed, 221 insertions, 46 deletions
diff --git a/lib/libpthread/Makefile b/lib/libpthread/Makefile index 6e689f263a1b..88dd8f2e380e 100644 --- a/lib/libpthread/Makefile +++ b/lib/libpthread/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.15 2020/06/21 07:06:05 lukem Exp $ +# $NetBSD: Makefile,v 1.22 2025/10/18 20:27:23 riastradh Exp $ NOMAN= # defined @@ -17,6 +17,8 @@ CPPFLAGS.t_condwait.c+= -I${.CURDIR}/../libc/gen TESTS_SH+= t_atexit TESTS_C+= t_barrier TESTS_SH+= t_cancel +TESTS_C+= t_cancellation +TESTS_C+= t_compat_cancel TESTS_C+= t_cond TESTS_C+= t_condwait TESTS_C+= t_detach @@ -37,11 +39,17 @@ TESTS_C+= t_sigmask TESTS_C+= t_sigsuspend TESTS_C+= t_siglongjmp TESTS_C+= t_sleep +TESTS_C+= t_stack TESTS_C+= t_swapcontext TESTS_SH+= t_thread_local_dtor TESTS_C+= t_timedmutex LDADD.t_sem+= -lrt +LDADD.t_cancellation+= -lrt +LDADD.t_compat_cancel+= -lrt +CPPFLAGS.t_compat_cancel.c+= -I${NETBSDSRCDIR}/lib/libc +CPPFLAGS.t_compat_cancel.c+= -I${NETBSDSRCDIR}/sys +LDFLAGS.t_compat_cancel+= -Wl,--no-fatal-warnings # intend compat use BINDIR= ${TESTSDIR} PROGS= h_atexit @@ -60,6 +68,7 @@ SRCS.h_thread_local_dtor= h_thread_local_dtor.cpp FILESDIR= ${TESTSDIR} FILES= d_mach -SUBDIR= dlopen +TESTS_SUBDIRS+= dlopen +TESTS_SUBDIRS+= weak .include <bsd.test.mk> diff --git a/lib/libpthread/dlopen/t_dlopen.c b/lib/libpthread/dlopen/t_dlopen.c index 68e983585431..fc7e5f831582 100644 --- a/lib/libpthread/dlopen/t_dlopen.c +++ b/lib/libpthread/dlopen/t_dlopen.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_dlopen.c,v 1.1 2013/03/21 16:50:21 christos Exp $ */ +/* $NetBSD: t_dlopen.c,v 1.3 2025/11/23 22:11:41 riastradh Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. @@ -32,28 +32,22 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_dlopen.c,v 1.1 2013/03/21 16:50:21 christos Exp $"); +__RCSID("$NetBSD: t_dlopen.c,v 1.3 2025/11/23 22:11:41 riastradh Exp $"); #include <atf-c.h> #include <dlfcn.h> #include <pthread.h> +#include <signal.h> #include <unistd.h> -ATF_TC(dlopen); - -ATF_TC_HEAD(dlopen, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO"); -} - #define DSO TESTDIR "/h_pthread_dlopen.so" -ATF_TC_BODY(dlopen, tc) +static void +test_dlopen(int flags) { void *handle; int (*testf_dso_null)(void); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_null = dlsym(handle, "testf_dso_null"); @@ -64,15 +58,30 @@ ATF_TC_BODY(dlopen, tc) ATF_REQUIRE(dlclose(handle) == 0); } -ATF_TC(dlopen_mutex); +ATF_TC(dlopen); +ATF_TC_HEAD(dlopen, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO"); +} +ATF_TC_BODY(dlopen, tc) +{ + test_dlopen(RTLD_NOW | RTLD_LOCAL); +} -ATF_TC_HEAD(dlopen_mutex, tc) +ATF_TC(dlopen_lazyglobal); +ATF_TC_HEAD(dlopen_lazyglobal, tc) { atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO without breaking mutex"); + "Test if dlopen can load -lpthread DSO"); +} +ATF_TC_BODY(dlopen_lazyglobal, tc) +{ + test_dlopen(RTLD_LAZY | RTLD_GLOBAL); } -ATF_TC_BODY(dlopen_mutex, tc) +static void +test_dlopen_mutex(int flags) { pthread_mutex_t mtx; void *handle; @@ -81,7 +90,7 @@ ATF_TC_BODY(dlopen_mutex, tc) ATF_REQUIRE(pthread_mutex_init(&mtx, NULL) == 0); ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_null = dlsym(handle, "testf_dso_null"); @@ -93,18 +102,36 @@ ATF_TC_BODY(dlopen_mutex, tc) ATF_REQUIRE(dlclose(handle) == 0); + ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); + ATF_REQUIRE(pthread_mutex_unlock(&mtx) == 0); + pthread_mutex_destroy(&mtx); } -ATF_TC(dlopen_mutex_libc); +ATF_TC(dlopen_mutex); +ATF_TC_HEAD(dlopen_mutex, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO without breaking mutex"); +} +ATF_TC_BODY(dlopen_mutex, tc) +{ + test_dlopen_mutex(RTLD_NOW | RTLD_LOCAL); +} -ATF_TC_HEAD(dlopen_mutex_libc, tc) +ATF_TC(dlopen_mutex_lazyglobal); +ATF_TC_HEAD(dlopen_mutex_lazyglobal, tc) { atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO and use libc locked mutex"); + "Test if dlopen can load -lpthread DSO without breaking mutex"); +} +ATF_TC_BODY(dlopen_mutex_lazyglobal, tc) +{ + test_dlopen_mutex(RTLD_LAZY | RTLD_GLOBAL); } -ATF_TC_BODY(dlopen_mutex_libc, tc) +static void +test_dlopen_mutex_libc(int flags) { pthread_mutex_t mtx; void *handle; @@ -113,7 +140,7 @@ ATF_TC_BODY(dlopen_mutex_libc, tc) ATF_REQUIRE(pthread_mutex_init(&mtx, NULL) == 0); ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_mutex_unlock = dlsym(handle, "testf_dso_mutex_unlock"); @@ -124,19 +151,36 @@ ATF_TC_BODY(dlopen_mutex_libc, tc) dlclose(handle); + ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); + ATF_REQUIRE(pthread_mutex_unlock(&mtx) == 0); + pthread_mutex_destroy(&mtx); } -ATF_TC(dlopen_mutex_libpthread); +ATF_TC(dlopen_mutex_libc); +ATF_TC_HEAD(dlopen_mutex_libc, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO and use libc locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libc, tc) +{ + test_dlopen_mutex_libc(RTLD_NOW | RTLD_LOCAL); +} -ATF_TC_HEAD(dlopen_mutex_libpthread, tc) +ATF_TC(dlopen_mutex_libc_lazyglobal); +ATF_TC_HEAD(dlopen_mutex_libc_lazyglobal, tc) { atf_tc_set_md_var(tc, "descr", - "Test if dlopen can load -lpthread DSO and use " - "libpthread locked mutex"); + "Test if dlopen can load -lpthread DSO and use libc locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libc_lazyglobal, tc) +{ + test_dlopen_mutex_libc(RTLD_LAZY | RTLD_GLOBAL); } -ATF_TC_BODY(dlopen_mutex_libpthread, tc) +static void +test_dlopen_mutex_libpthread(int flags) { pthread_mutex_t mtx; void *handle; @@ -144,7 +188,7 @@ ATF_TC_BODY(dlopen_mutex_libpthread, tc) ATF_REQUIRE(pthread_mutex_init(&mtx, NULL) == 0); - handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(DSO, flags); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_mutex_lock = dlsym(handle, "testf_dso_mutex_lock"); @@ -157,15 +201,48 @@ ATF_TC_BODY(dlopen_mutex_libpthread, tc) dlclose(handle); + ATF_REQUIRE(pthread_mutex_lock(&mtx) == 0); + ATF_REQUIRE(pthread_mutex_unlock(&mtx) == 0); + pthread_mutex_destroy(&mtx); } +ATF_TC(dlopen_mutex_libpthread); +ATF_TC_HEAD(dlopen_mutex_libpthread, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO and use " + "libpthread locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libpthread, tc) +{ + test_dlopen_mutex_libpthread(RTLD_NOW | RTLD_LOCAL); +} + +ATF_TC(dlopen_mutex_libpthread_lazyglobal); +ATF_TC_HEAD(dlopen_mutex_libpthread_lazyglobal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test if dlopen can load -lpthread DSO and use " + "libpthread locked mutex"); +} +ATF_TC_BODY(dlopen_mutex_libpthread_lazyglobal, tc) +{ + test_dlopen_mutex_libpthread(RTLD_LAZY | RTLD_GLOBAL); +} + ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, dlopen); ATF_TP_ADD_TC(tp, dlopen_mutex); ATF_TP_ADD_TC(tp, dlopen_mutex_libc); ATF_TP_ADD_TC(tp, dlopen_mutex_libpthread); + ATF_TP_ADD_TC(tp, dlopen_lazyglobal); + ATF_TP_ADD_TC(tp, dlopen_mutex_lazyglobal); + ATF_TP_ADD_TC(tp, dlopen_mutex_libc_lazyglobal); + ATF_TP_ADD_TC(tp, dlopen_mutex_libpthread_lazyglobal); + return atf_no_error(); } diff --git a/lib/libpthread/dlopen/t_dso_pthread_create.c b/lib/libpthread/dlopen/t_dso_pthread_create.c index ab8bec32a8ab..93eee37e2dbc 100644 --- a/lib/libpthread/dlopen/t_dso_pthread_create.c +++ b/lib/libpthread/dlopen/t_dso_pthread_create.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_dso_pthread_create.c,v 1.1 2013/03/21 16:50:21 christos Exp $ */ +/* $NetBSD: t_dso_pthread_create.c,v 1.2 2025/11/22 20:05:20 riastradh Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. @@ -32,14 +32,17 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_dso_pthread_create.c,v 1.1 2013/03/21 16:50:21 christos Exp $"); +__RCSID("$NetBSD: t_dso_pthread_create.c,v 1.2 2025/11/22 20:05:20 riastradh Exp $"); -#include <sys/resource.h> #include <atf-c.h> #include <dlfcn.h> #include <pthread.h> +#include <setjmp.h> +#include <signal.h> #include <unistd.h> +#include "../../../h_macros.h" + #define DSO TESTDIR "/h_pthread_dlopen.so" void * @@ -49,6 +52,17 @@ routine(void *arg) return NULL; } +static jmp_buf abort_aborting; + +static void +handle_sigabrt(int signo) +{ + + ATF_REQUIRE_EQ_MSG(signo, SIGABRT, "signo=%d (%s)", signo, + strsignal(signo)); + longjmp(abort_aborting, 1); +} + ATF_TC(dso_pthread_create_dso); ATF_TC_HEAD(dso_pthread_create_dso, tc) @@ -64,25 +78,26 @@ ATF_TC_BODY(dso_pthread_create_dso, tc) pthread_t thread; void *arg = (void *)0xcafe; void *handle; - int (*testf_dso_pthread_create)(pthread_t *, pthread_attr_t *, + int (*testf_dso_pthread_create)(pthread_t *, pthread_attr_t *, void *(*)(void *), void *); - struct rlimit rl; - - atf_tc_expect_signal(6, - "calling pthread_create() requires -lpthread main"); - - rl.rlim_max = rl.rlim_cur = 0; - ATF_REQUIRE_EQ(setrlimit(RLIMIT_CORE, &rl), 0); + void (*sighandler)(int); handle = dlopen(DSO, RTLD_NOW | RTLD_LOCAL); ATF_REQUIRE_MSG(handle != NULL, "dlopen fails: %s", dlerror()); testf_dso_pthread_create = dlsym(handle, "testf_dso_pthread_create"); - ATF_REQUIRE_MSG(testf_dso_pthread_create != NULL, + ATF_REQUIRE_MSG(testf_dso_pthread_create != NULL, "dlsym fails: %s", dlerror()); - ret = testf_dso_pthread_create(&thread, NULL, routine, arg); - ATF_REQUIRE(ret == 0); + REQUIRE_LIBC((sighandler = signal(SIGABRT, &handle_sigabrt)), SIG_ERR); + if (setjmp(abort_aborting) == 0) { + ret = testf_dso_pthread_create(&thread, NULL, routine, arg); + } else { + ret = ENOSYS; + } + REQUIRE_LIBC(signal(SIGABRT, sighandler), SIG_ERR); + ATF_REQUIRE_MSG(ret != 0, + "pthread_create unexpectedly succeeded"); ATF_REQUIRE(dlclose(handle) == 0); diff --git a/lib/libpthread/t_once.c b/lib/libpthread/t_once.c index 650f3ee68dfd..add6f07cc9da 100644 --- a/lib/libpthread/t_once.c +++ b/lib/libpthread/t_once.c @@ -1,4 +1,4 @@ -/* $NetBSD: t_once.c,v 1.2 2017/08/25 22:59:47 ginsbach Exp $ */ +/* $NetBSD: t_once.c,v 1.3 2025/03/30 23:03:06 riastradh Exp $ */ /* * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -29,17 +29,21 @@ #include <sys/cdefs.h> __COPYRIGHT("@(#) Copyright (c) 2008\ The NetBSD Foundation, inc. All rights reserved."); -__RCSID("$NetBSD: t_once.c,v 1.2 2017/08/25 22:59:47 ginsbach Exp $"); +__RCSID("$NetBSD: t_once.c,v 1.3 2025/03/30 23:03:06 riastradh Exp $"); #include <sys/time.h> +#include <sys/wait.h> + #include <pthread.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <atf-c.h> #include "h_common.h" +#include "h_macros.h" static pthread_once_t once = PTHREAD_ONCE_INIT; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -54,6 +58,12 @@ ofunc(void) x++; } +static void +ofunc_silent(void) +{ + x++; +} + ATF_TC(once1); ATF_TC_HEAD(once1, tc) { @@ -187,11 +197,75 @@ ATF_TC_BODY(once3, tc) printf("Test succeeded\n"); } +static long trial; + +static void * +fork_and_once(void *cookie) +{ + pthread_barrier_t *bar = cookie; + pid_t pid, child; + int status; + + (void)pthread_barrier_wait(bar); + RL(pid = fork()); + if (pid == 0) { + (void)alarm(1); + (void)pthread_once(&once, &ofunc_silent); + _exit(x - 1); + } + RL(child = waitpid(pid, &status, 0)); + ATF_REQUIRE_EQ_MSG(child, pid, "child=%lld pid=%lld", + (long long)child, (long long)pid); + ATF_REQUIRE_MSG(!WIFSIGNALED(status), + "child exited on signal %d (%s) in trial %ld", + WTERMSIG(status), strsignal(WTERMSIG(status)), trial); + ATF_REQUIRE_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "child exited 0x%x in trial %ld", status, trial); + return NULL; +} + +ATF_TC(oncefork); +ATF_TC_HEAD(oncefork, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test racing pthread_once with fork"); +} +ATF_TC_BODY(oncefork, tc) +{ + static pthread_once_t once0 = PTHREAD_ONCE_INIT; + pthread_barrier_t bar; + long ntrials = atf_tc_get_config_var_as_long_wd(tc, + "pthread_once_forktrials", 0); + + if (ntrials <= 0) { + atf_tc_skip("pthread_once takes thousands of fork trials" + " on a multicore system to detect a race; set" + " pthread_once_forktrials to the number of trials to" + " enable this test"); + } + + RZ(pthread_barrier_init(&bar, NULL, 2)); + + for (trial = 0; trial < ntrials; trial++) { + pthread_t t; + + once = once0; + x = 0; + + RZ(pthread_create(&t, NULL, &fork_and_once, &bar)); + (void)alarm(1); + (void)pthread_barrier_wait(&bar); + (void)pthread_once(&once, &ofunc_silent); + (void)alarm(0); + RZ(pthread_join(t, NULL)); + } +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, once1); ATF_TP_ADD_TC(tp, once2); ATF_TP_ADD_TC(tp, once3); + ATF_TP_ADD_TC(tp, oncefork); return atf_no_error(); } |
