diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile index bb9542b185e..a8209209e7e 100644 --- a/lib/libc/tests/stdlib/Makefile +++ b/lib/libc/tests/stdlib/Makefile @@ -2,6 +2,7 @@ .include +ATF_TESTS_C+= dynthr_test ATF_TESTS_C+= heapsort_test ATF_TESTS_C+= mergesort_test ATF_TESTS_C+= qsort_test @@ -13,6 +14,10 @@ ATF_TESTS_CXX+= cxa_thread_atexit_test ATF_TESTS_CXX+= cxa_thread_atexit_nothr_test .endif +dynthr_mod.so: dynthr_test.c + ${CC} -Wall -DMODULE -fPIC -shared -pthread -o ${.TARGET} \ + ${.CURDIR}/dynthr_test.c + # Not sure why this isn't defined for all architectures, since most # have long double. .if ${MACHINE_CPUARCH} == "aarch64" || \ @@ -63,3 +68,6 @@ LIBADD.${t}+= netbsd util LIBADD.strtod_test+= m .include +# Placed here because bsd.test.mk is where PACKAGE gets defaulted, if not +# otherwise defined. +${PACKAGE}FILES+= dynthr_mod.so diff --git a/lib/libc/tests/stdlib/dynthr_test.c b/lib/libc/tests/stdlib/dynthr_test.c new file mode 100644 index 00000000000..cb984ea0d64 --- /dev/null +++ b/lib/libc/tests/stdlib/dynthr_test.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 Andrew Gierth + * SPDX-License-Identifier: BSD-2-Clause + * + * Though this file is initially distributed under the 2-clause BSD license, + * the author grants permission for its redistribution under alternative + * licenses as set forth at . + * This paragraph and the RELICENSE.txt file are not part of the license and + * may be omitted in redistributions. + */ + +#include +#include +#include +#include +#include + +#include + +#ifdef MODULE +#include +#else +#include +#endif + +#define say(...) +#define die(...) _exit(1) + +typedef void (modfunc_t)(int op); + +#ifdef MODULE + +static void *mod_thread(void *ptr) +{ + char *volatile dummy; + dummy = malloc(500); + dummy = malloc(500); + return NULL; +} + +modfunc_t mod_main; + +static pthread_t thr; + +void mod_main(int op) +{ + char *volatile dummy; + switch (op) + { + case 1: + { + int rc = pthread_create(&thr, NULL, mod_thread, NULL); + if (rc) + die("thread creation failed: %s", strerror(rc)); + dummy = malloc(500); + say("thread started"); + return; + } + case 0: + { + say("waiting for thread"); + pthread_join(thr, NULL); + say("thread stopped"); + return; + } + } +} + +#else + +ATF_TC(maintc); +ATF_TC_HEAD(maintc, tc) +{ + atf_tc_set_md_var(tc, "timeout", "5"); +} + +ATF_TC_BODY(maintc, tc) +{ + const char *srcdir; + char *libpath; + char *volatile dummy; + say("starting"); + + srcdir = atf_tc_get_config_var(tc, "srcdir"); +#ifdef PRELOAD_LIBTHR + void *thr_handle = dlopen("libthr.so", RTLD_GLOBAL|RTLD_NOW); + if (!thr_handle) + atf_tc_fail("failed to open libthr.so: %s", dlerror()); +#endif + if (asprintf(&libpath, "%s/dynthr_mod.so", srcdir) < 0) + atf_tc_fail("failed to construct path to libthr"); + void *mod_handle = dlopen(libpath, RTLD_LOCAL); + free(libpath); + if (!mod_handle) + atf_tc_fail("failed to open dynthr_mod.so: %s", dlerror()); + say("module loaded"); + dlfunc_t rawfunc = dlfunc(mod_handle, "mod_main"); + if (!rawfunc) + atf_tc_fail("failed to resolve function mod_main"); + say("invoking module"); + modfunc_t *func = (modfunc_t *) rawfunc; + func(1); + dummy = malloc(500); + say("done; invoking module stop"); + func(0); + say("stopped successfully"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, maintc); + + return atf_no_error(); +} +#endif