Index: etc/mtree/BSD.tests.dist =================================================================== --- etc/mtree/BSD.tests.dist +++ etc/mtree/BSD.tests.dist @@ -87,6 +87,10 @@ test-programs .. .. + libc + net + .. + .. libcrypt .. libmp Index: lib/libc/Makefile =================================================================== --- lib/libc/Makefile +++ lib/libc/Makefile @@ -158,6 +158,10 @@ cp -fp ${.ALLSRC} ${DESTDIR}/sys/libkern/${LIBC_ARCH} .endif +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + .include # Disable warnings in contributed sources. Index: lib/libc/net/nsdispatch.c =================================================================== --- lib/libc/net/nsdispatch.c +++ lib/libc/net/nsdispatch.c @@ -329,7 +329,6 @@ static int nss_configure(void) { - static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER; static time_t confmod; struct stat statbuf; int result, isthreaded; @@ -353,13 +352,14 @@ if (statbuf.st_mtime <= confmod) return (0); if (isthreaded) { - result = _pthread_mutex_trylock(&conf_lock); - if (result != 0) - return (0); (void)_pthread_rwlock_unlock(&nss_lock); result = _pthread_rwlock_wrlock(&nss_lock); if (result != 0) - goto fin2; + return (result); + if (stat(path, &statbuf) != 0) + goto fin; + if (statbuf.st_mtime <= confmod) + goto fin; } _nsyyin = fopen(path, "re"); if (_nsyyin == NULL) @@ -385,14 +385,10 @@ } #endif fin: - if (isthreaded) { - (void)_pthread_rwlock_unlock(&nss_lock); - if (result == 0) - result = _pthread_rwlock_rdlock(&nss_lock); - } -fin2: if (isthreaded) - (void)_pthread_mutex_unlock(&conf_lock); + (void)_pthread_rwlock_unlock(&nss_lock); + if (isthreaded && result == 0) + result = _pthread_rwlock_rdlock(&nss_lock); return (result); } Index: lib/libc/tests/Makefile =================================================================== --- /dev/null +++ lib/libc/tests/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/lib/libc + +TESTS_SUBDIRS+= net + +.include Index: lib/libc/tests/net/Makefile =================================================================== --- /dev/null +++ lib/libc/tests/net/Makefile @@ -0,0 +1,12 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/lib/libc/net + +ATF_TESTS_SH+= t_nsdispatch + +PROGS+= h_nsd_parallel +BINDIR.h_nsd_parallel= ${TESTSDIR} +LDADD.h_nsd_parallel= -lpthread +DPADD.h_nsd_parallel= ${LIBPTHREAD} + +.include Index: lib/libc/tests/net/h_nsd_parallel.c =================================================================== --- /dev/null +++ lib/libc/tests/net/h_nsd_parallel.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2014 EMC Corp. + * All rights reserved. + * + * 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. + */ + +/* + * A little test program for parallel name lookups. This program is invoked + * from a shell wrapper instead of using ATF directly, since we want to be + * sure that something like a username lookup hasn't caused libc to parse + * nsswitch.conf before we call nsdispatch(3). + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include + +static int nssrc_func(void *, void *, va_list); +static void * thr_func(void *); + +#define MAGICVAL 1729 + +static int +nssrc_func(void *retval, void *mdata, va_list ap) +{ + int *_retval = retval; + + *_retval = MAGICVAL; + return (NS_SUCCESS); +} + +static void * +thr_func(void *arg __unused) +{ + const ns_dtab dtab[] = { + { NSSRC_FALLBACK, nssrc_func, NULL }, + { NULL, NULL, NULL }, + }; + const ns_src defaultsrc[] = { + { NULL, 0 }, + }; + int error, ret; + + ret = 0; + error = nsdispatch(&ret, dtab, NSDB_PASSWD, "test", defaultsrc); + if (error != NS_SUCCESS) + errx(1, "name lookup failed: %d", error); + if (ret != MAGICVAL) + errx(1, "fallback name source wasn't queried"); + return (NULL); +} + +int +main(int argc, char **argv) +{ + const int numthr = 10; + pthread_t tids[numthr]; + int error; + + for (int i = 0; i < numthr; i++) { + error = pthread_create(&tids[i], NULL, thr_func, NULL); + if (error != 0) + errx(1, "pthread_create failed: %s", strerror(error)); + } + for (int i = 0; i < numthr; i++) { + error = pthread_join(tids[i], NULL); + if (error != 0) + errx(1, "pthread_join failed: %s", strerror(error)); + } + return (0); +} Index: lib/libc/tests/net/t_nsdispatch.sh =================================================================== --- /dev/null +++ lib/libc/tests/net/t_nsdispatch.sh @@ -0,0 +1,46 @@ +# +# Copyright (c) 2014 EMC Corp. +# All rights reserved. +# +# 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. +# +# $FreeBSD$ +# + +atf_test_case parallel_configure +parallel_configure_head() +{ + atf_set "descr" \ + "Attempt to call nsdispatch(3) concurrently from several threads." \ + "When these threads race to parse nsswitch.conf, losers should" \ + "wait for the winner to finish parsing rather than falling back" \ + "to the default sources for the database." +} +parallel_configure_body() +{ + atf_check -s exit:0 -o empty -e empty "$(atf_get_srcdir)/h_nsd_parallel" +} + +atf_init_test_cases() +{ + atf_add_test_case parallel_configure +}