From patchwork Mon Jul 1 16:31:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 33501 Received: (qmail 13024 invoked by alias); 1 Jul 2019 16:31:34 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 13015 invoked by uid 89); 1 Jul 2019 16:31:34 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx1.redhat.com From: Florian Weimer To: Carlos O'Donell Cc: libc-alpha@sourceware.org Subject: Re: [PATCH] nptl: Add test nptl/tst-pthread-perthread-inherit References: <8736jtlbl6.fsf@oldenburg2.str.redhat.com> <48ae254c-d421-d6e1-6438-22a683c15083@redhat.com> Date: Mon, 01 Jul 2019 18:31:26 +0200 In-Reply-To: <48ae254c-d421-d6e1-6438-22a683c15083@redhat.com> (Carlos O'Donell's message of "Sun, 30 Jun 2019 01:02:20 -0400") Message-ID: <87woh1af8h.fsf@oldenburg2.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) MIME-Version: 1.0 I had to fix a race condition related to the use of pthread_getattr_np. I believe the patch below should address your concerns. Thanks, Florian nptl: Add test nptl/tst-pthread-perthread-inherit This test checks the inheritance behavior of the per-thread flags. It is also a regular (non-xtest) for pthread_attr_setperthreadids_np and pthread_attr_getperthreadids_np. 2019-06-28 Florian Weimer * nptl/Makefile (tests): Add tst-pthread-perthread-inherit. * nptl/tst-pthread-perthread-inherit.c: New file. Reviewed-by: Carlos O'Donell diff --git a/nptl/Makefile b/nptl/Makefile index 52913cc2f0..56f1578860 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -324,7 +324,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-rwlock-pwn \ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \ tst-unwind-thread \ - tst-pthread-perthreadfs tst-pthread-perthreadfs-chroot + tst-pthread-perthreadfs tst-pthread-perthreadfs-chroot \ + tst-pthread-perthread-inherit tests-internal := tst-rwlock19 tst-rwlock20 \ tst-sem11 tst-sem12 tst-sem13 \ diff --git a/nptl/tst-pthread-perthread-inherit.c b/nptl/tst-pthread-perthread-inherit.c new file mode 100644 index 0000000000..99feb01dc9 --- /dev/null +++ b/nptl/tst-pthread-perthread-inherit.c @@ -0,0 +1,220 @@ +/* Test inheritance of per-thread attributes. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include + +/* Controls how an attribute is applied. */ +enum kind { null_attribute, default_attribute, attribute_per_process, + attribute_per_thread }; + +/* Determine the combined per-thread/per-process status from the two + requested attributes. */ +static int +combine_kind (enum kind a, enum kind b) +{ + if (a == attribute_per_thread || b == attribute_per_thread) + return PTHREAD_PER_THREAD_NP; + else + return PTHREAD_PER_PROCESS_NP; +} + +/* Convert one kind to the corresponding PTHREAD_PER_PROCESS_NP, + PTHREAD_PER_THREAD_NP flag. */ +static int +convert_kind (enum kind k) +{ + if (k == attribute_per_thread) + return PTHREAD_PER_THREAD_NP; + else + return PTHREAD_PER_PROCESS_NP; +} + +/* Return either PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP. */ +static int +scope (pthread_t thr, int (*getter) (const pthread_attr_t *, int *)) +{ + pthread_attr_t attr; + int ret = pthread_getattr_np (thr, &attr); + if (ret != 0) + { + errno = ret; + FAIL_EXIT1 ("pthread_getattr_np: %m"); + } + int flag = -1; + TEST_COMPARE (getter (&attr, &flag), 0); + if (flag != PTHREAD_PER_THREAD_NP) + TEST_COMPARE (flag, PTHREAD_PER_PROCESS_NP); + xpthread_attr_destroy (&attr); + return flag; +} + +/* The loop in do_test iterates through the Cartesian product of all + possible values. */ +static enum kind outer_perthreadfs; +static enum kind inner_perthreadfs; +static enum kind outer_perthreadids; +static enum kind inner_perthreadids; + +/* Used to prevent premature thread exit, so that we can safely call + pthread_getattr_np. */ +static pthread_barrier_t barrier; + +static void * +inner_thread (void *closure) +{ + TEST_COMPARE (scope (pthread_self (), + pthread_attr_getperthreadfs_np), + combine_kind (outer_perthreadfs, inner_perthreadfs)); + TEST_COMPARE (scope (pthread_self (), + pthread_attr_getperthreadids_np), + combine_kind (outer_perthreadids, inner_perthreadids)); + /* Delay exit of the thread until the outer thread has read the + attributes. */ + xpthread_barrier_wait (&barrier); + return NULL; +} + +static void * +outer_thread (void *attr) +{ + TEST_COMPARE (scope (pthread_self (), + pthread_attr_getperthreadfs_np), + convert_kind (outer_perthreadfs)); + TEST_COMPARE (scope (pthread_self (), + pthread_attr_getperthreadids_np), + convert_kind (outer_perthreadids)); + pthread_t thr = xpthread_create (attr, inner_thread, NULL); + TEST_COMPARE (scope (thr, pthread_attr_getperthreadfs_np), + combine_kind (outer_perthreadfs, inner_perthreadfs)); + TEST_COMPARE (scope (thr, pthread_attr_getperthreadids_np), + combine_kind (outer_perthreadids, inner_perthreadids)); + /* Delay exit of the thread until the main thread has read the + attributes. */ + xpthread_barrier_wait (&barrier); + return xpthread_join (thr); +} + +/* Apply the attribute KIND according to SETTER to ATTR. */ +static void +attribute_apply (pthread_attr_t *attr, enum kind kind, + int (*setter) (pthread_attr_t *attr, int)) +{ + switch (kind) + { + case default_attribute: + return; + + case attribute_per_process: + case attribute_per_thread: + TEST_COMPARE (setter (attr, convert_kind (kind)), 0); + return; + + case null_attribute: + /* Report failure below. */ + ; + } + + FAIL_EXIT1 ("invalid kind: %d", (int) kind); +} + +/* Create a new attribute according to both kinds. */ +static pthread_attr_t * +make_attribute (enum kind perthreadfs, enum kind perthreadids) +{ + if (perthreadfs == null_attribute) + { + TEST_COMPARE (perthreadids, null_attribute); + return NULL; + } + pthread_attr_t *result = xmalloc (sizeof (*result)); + xpthread_attr_init (result); + attribute_apply (result, perthreadfs, pthread_attr_setperthreadfs_np); + attribute_apply (result, perthreadids, pthread_attr_setperthreadids_np); + return result; +} + +/* Deallocate the attribute pointer returned from make_attribute. */ +static void +free_attribute (pthread_attr_t *attr) +{ + if (attr != NULL) + { + xpthread_attr_destroy (attr); + free (attr); + } +} + +static int +do_test (void) +{ + /* Used to delay thread exit, so that pthread_getattr_np works + reliably. Inner thread, outer thread, and main thread are + waiting. */ + xpthread_barrier_init (&barrier, NULL, 3); + + for (outer_perthreadfs = null_attribute; + outer_perthreadfs <= attribute_per_thread; + ++outer_perthreadfs) + for (inner_perthreadfs = null_attribute; + inner_perthreadfs <= attribute_per_thread; + ++inner_perthreadfs) + for (outer_perthreadids = null_attribute; + outer_perthreadids <= attribute_per_thread; + ++outer_perthreadids) + for (inner_perthreadids = null_attribute; + inner_perthreadids <= attribute_per_thread; + ++inner_perthreadids) + { + /* Some combinations are impossible. If we must pass a + NULL attribute at one level, then that is true for both + kinds of properties. */ + if ((outer_perthreadfs == null_attribute) + != (outer_perthreadids == null_attribute)) + continue; + if ((inner_perthreadfs == null_attribute) + != (inner_perthreadids == null_attribute)) + continue; + + pthread_attr_t *outer_attr + = make_attribute (outer_perthreadfs, outer_perthreadids); + pthread_attr_t *inner_attr + = make_attribute (inner_perthreadfs, inner_perthreadids); + pthread_t thr = xpthread_create (outer_attr, + outer_thread, inner_attr); + TEST_COMPARE (scope (thr, pthread_attr_getperthreadfs_np), + convert_kind (outer_perthreadfs)); + TEST_COMPARE (scope (thr, pthread_attr_getperthreadids_np), + convert_kind (outer_perthreadids)); + /* The threads may now exit, after we have checked the + attributes. */ + xpthread_barrier_wait (&barrier); + xpthread_join (thr); + free_attribute (inner_attr); + free_attribute (outer_attr); + } + + xpthread_barrier_destroy (&barrier); + return 0; +} + +#include