diff --git a/lib/libthr/tests/Makefile b/lib/libthr/tests/Makefile index 8b7850b94265..d882ccfd877c 100644 --- a/lib/libthr/tests/Makefile +++ b/lib/libthr/tests/Makefile @@ -1,58 +1,59 @@ PACKAGE= tests WARNS?= 3 TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread # 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 .if ${MACHINE_CPUARCH} != "aarch64" # ARM64TODO: Missing makecontext NETBSD_ATF_TESTS_C+= swapcontext_test .endif NETBSD_ATF_TESTS_C+= timedmutex_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 ATF_TESTS_C+= umtx_op_test +ATF_TESTS_C+= pthread_sigqueue_test LIBADD+= pthread LIBADD.fpu_test+= m LIBADD.sem_test+= rt BINDIR= ${TESTSDIR} PROGS= h_atexit PROGS+= h_cancel PROGS+= h_exit PROGS+= h_resolv ${PACKAGE}FILES+= d_mach TESTS_SUBDIRS= dlopen .include CFLAGS.condwait_test+= -I${SRCTOP}/contrib/netbsd-tests/lib/libc/gen .include diff --git a/lib/libthr/tests/pthread_sigqueue_test.c b/lib/libthr/tests/pthread_sigqueue_test.c new file mode 100644 index 000000000000..053a8dac4039 --- /dev/null +++ b/lib/libthr/tests/pthread_sigqueue_test.c @@ -0,0 +1,120 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2024 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov + * 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NTHREADS 330 +static int value[NTHREADS]; +static pthread_t thr[NTHREADS]; +static pthread_barrier_t barrier; + +static void +handler(int signo __unused, siginfo_t *info, void *data __unused) +{ + pthread_t self; + int i; + + /* + * Formally this is thread-unsafe but we know context from + * where the signal is sent. + */ + self = pthread_self(); + for (i = 0; i < NTHREADS; i++) { + if (pthread_equal(self, thr[i])) { + value[i] = info->si_value.sival_int; + pthread_exit(NULL); + } + } +} + +static void * +threadfunc(void *arg __unused) +{ + pthread_barrier_wait(&barrier); + for (;;) + pause(); +} + +ATF_TC(pthread_sigqueue); +ATF_TC_HEAD(pthread_sigqueue, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks pthread_sigqueue(3) sigval delivery"); +} + +ATF_TC_BODY(pthread_sigqueue, tc) +{ + struct sigaction sa; + union sigval sv; + int error, i; + + error = pthread_barrier_init(&barrier, NULL, NTHREADS + 1); + ATF_REQUIRE_EQ(0, error); + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction(SIGUSR1, &sa, NULL) != 0) + atf_tc_fail("sigaction failed"); + + memset(&sv, 0, sizeof(sv)); + + for (i = 0; i < NTHREADS; i++) { + error = pthread_create(&thr[i], NULL, threadfunc, NULL); + ATF_REQUIRE_EQ(0, error); + } + error = pthread_barrier_wait(&barrier); + ATF_REQUIRE(error == 0 || error == PTHREAD_BARRIER_SERIAL_THREAD); + + for (i = 0; i < NTHREADS; i++) { + sv.sival_int = i + 1000; + error = pthread_sigqueue(thr[i], SIGUSR1, sv); + ATF_REQUIRE_EQ(0, error); + error = pthread_join(thr[i], NULL); + ATF_REQUIRE_EQ(0, error); + } + for (i = 0; i < NTHREADS; i++) + ATF_REQUIRE_EQ(i + 1000, value[i]); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, pthread_sigqueue); + return atf_no_error(); +}