From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-3.6 required=3.0 tests=AWL,BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dcvr.yhbt.net (Postfix) with ESMTPS id C62FD1F5AE for ; Wed, 1 Jul 2020 20:10:25 +0000 (UTC) Received: from localhost ([::1]:37076 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jqj3o-00006H-D1 for normalperson@yhbt.net; Wed, 01 Jul 2020 16:10:24 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:48494) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jqj3f-00004q-4E for bug-gnulib@gnu.org; Wed, 01 Jul 2020 16:10:15 -0400 Received: from mo4-p00-ob.smtp.rzone.de ([81.169.146.162]:13973) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jqj3X-0003QG-4X for bug-gnulib@gnu.org; Wed, 01 Jul 2020 16:10:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1593634202; s=strato-dkim-0002; d=clisp.org; h=Message-ID:Date:Subject:To:From:X-RZG-CLASS-ID:X-RZG-AUTH:From: Subject:Sender; bh=Cvw3oQ9ctl9NuiyRI0MviAYICZIkTCJwXu+1aTOWbtE=; b=nSIQdyg4U5AegsUTCsy74BzXlyg82LFvpVn7Tu6cmcDt12octGGkcIFMNG8no1n8aP 5MYrIsCfjJruPUp20czcfaW8p8NDzvMumFg/Gynct2x4mfkHPFXWnzP12fhvyfC4dlkO lkPQa8xV2uPBlchg7+H0+pRtbUY/piI0g4p4EyTc4QsquR6VdmL/k97MH0KGueDlTMFn dM3maH41fylcOox+C5e+U4L4fqIlITDyf3kMK7JKAD/mP1F4r/9ipRdkhan1shDInpGx eo3cr7eCHNDkzXRUZUnkI8gv1VStaNdQ87rsc/DgZir95DUIyr5XohqP53RuyzLoxZTr oSQg== X-RZG-AUTH: ":Ln4Re0+Ic/6oZXR1YgKryK8brlshOcZlIWs+iCP5vnk6shH+AHjwLuWOH6fzxfs=" X-RZG-CLASS-ID: mo00 Received: from bruno.haible.de by smtp.strato.de (RZmta 46.10.5 DYNA|AUTH) with ESMTPSA id R03d1aw61KA1lC2 (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (curve X9_62_prime256v1 with 256 ECDH bits, eq. 3072 bits RSA)) (Client did not present a certificate); Wed, 1 Jul 2020 22:10:01 +0200 (CEST) From: Bruno Haible To: bug-gnulib@gnu.org Subject: pthread-spin: add tests Date: Wed, 01 Jul 2020 22:10:00 +0200 Message-ID: <1833208.Xh3nXCtZ5K@omega> User-Agent: KMail/5.1.3 (Linux/4.4.0-179-generic; KDE/5.18.0; x86_64; ; ) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart3762119.ruPitNfY6I" Content-Transfer-Encoding: 7Bit Received-SPF: none client-ip=81.169.146.162; envelope-from=bruno@clisp.org; helo=mo4-p00-ob.smtp.rzone.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/07/01 16:10:02 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_PASS=-0.001, SPF_NONE=0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: bug-gnulib@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Gnulib discussion list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnulib-bounces+normalperson=yhbt.net@gnu.org Sender: "bug-gnulib" This is a multi-part message in MIME format. --nextPart3762119.ruPitNfY6I Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" This patch series 1) reduces code duplication among the lock and mutex tests. 2) adds a unit test for the 'pthread-spin' module. 2020-07-01 Bruno Haible pthread-spin: Add tests. * tests/test-pthread-spin.c: New file, based on tests/test-lock.c. * modules/pthread-spin-tests: New file. 2020-07-01 Bruno Haible tests: Reduce code duplication. * tests/atomic-int-posix.h: New file, extracted from tests/test-pthread-mutex.c. * tests/test-pthread-mutex.c: Include it. Remove the corresponding code. * tests/test-pthread-rwlock.c: Likewise. * modules/pthread-mutex-tests (Files): Add tests/atomic-int-posix.h. * modules/pthread-rwlock-tests (Files): Likewise. 2020-07-01 Bruno Haible tests: Refactor. * tests/atomic-int-isoc.h: New file, extracted from tests/test-mtx.c. * tests/test-mtx.c: Include it. Remove the corresponding code. * modules/mtx-tests (Files): Add tests/atomic-int-isoc.h. 2020-07-01 Bruno Haible tests: Refactor. * tests/atomic-int-gnulib.h: New file, extracted from tests/test-lock.c. * tests/test-lock.c: Include it. Remove the corresponding code. * modules/lock-tests (Files): Add tests/atomic-int-gnulib.h. --nextPart3762119.ruPitNfY6I Content-Disposition: attachment; filename="0001-tests-Refactor.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0001-tests-Refactor.patch" >From 6ace6219e9804cfa643cd950494e36fab2fcc4da Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 1 Jul 2020 22:05:15 +0200 Subject: [PATCH 1/4] tests: Refactor. * tests/atomic-int-gnulib.h: New file, extracted from tests/test-lock.c. * tests/test-lock.c: Include it. Remove the corresponding code. * modules/lock-tests (Files): Add tests/atomic-int-gnulib.h. --- ChangeLog | 7 ++ modules/lock-tests | 1 + tests/atomic-int-gnulib.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++ tests/test-lock.c | 156 +---------------------------------------- 4 files changed, 183 insertions(+), 154 deletions(-) create mode 100644 tests/atomic-int-gnulib.h diff --git a/ChangeLog b/ChangeLog index 9005fa3..d6c59e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2020-07-01 Bruno Haible + + tests: Refactor. + * tests/atomic-int-gnulib.h: New file, extracted from tests/test-lock.c. + * tests/test-lock.c: Include it. Remove the corresponding code. + * modules/lock-tests (Files): Add tests/atomic-int-gnulib.h. + 2020-06-29 Bruno Haible sys_socket: Don't define socklen_t if it is already defined on mingw. diff --git a/modules/lock-tests b/modules/lock-tests index 112fbf9..31d627d 100644 --- a/modules/lock-tests +++ b/modules/lock-tests @@ -2,6 +2,7 @@ Files: tests/test-rwlock1.c tests/test-lock.c tests/test-once.c +tests/atomic-int-gnulib.h m4/semaphore.m4 Depends-on: diff --git a/tests/atomic-int-gnulib.h b/tests/atomic-int-gnulib.h new file mode 100644 index 0000000..82e11a9 --- /dev/null +++ b/tests/atomic-int-gnulib.h @@ -0,0 +1,173 @@ +/* Atomic integers. Useful for testing multithreaded locking primitives. + Copyright (C) 2005, 2008-2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +/* Whether to use 'volatile' on some variables that communicate information + between threads. If set to 0, a semaphore or a lock is used to protect + these variables. If set to 1, 'volatile' is used; this is theoretically + equivalent but can lead to much slower execution (e.g. 30x slower total + run time on a 40-core machine), because 'volatile' does not imply any + synchronization/communication between different CPUs. */ +#define USE_VOLATILE 0 + +#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H +/* Whether to use a semaphore to communicate information between threads. + If set to 0, a lock is used. If set to 1, a semaphore is used. + Uncomment this to reduce the dependencies of this test. */ +# define USE_SEMAPHORE 1 +/* Mac OS X provides only named semaphores (sem_open); its facility for + unnamed semaphores (sem_init) does not work. */ +# if defined __APPLE__ && defined __MACH__ +# define USE_NAMED_SEMAPHORE 1 +# else +# define USE_UNNAMED_SEMAPHORE 1 +# endif +#endif + + +#if USE_SEMAPHORE +# include +# include +# include +# include +#endif + + +#if USE_VOLATILE +struct atomic_int { + volatile int value; +}; +static void +init_atomic_int (struct atomic_int *ai) +{ +} +static int +get_atomic_int_value (struct atomic_int *ai) +{ + return ai->value; +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + ai->value = new_value; +} +#elif USE_SEMAPHORE +/* This atomic_int implementation can only support the values 0 and 1. + It is initially 0 and can be set to 1 only once. */ +# if USE_UNNAMED_SEMAPHORE +struct atomic_int { + sem_t semaphore; +}; +#define atomic_int_semaphore(ai) (&(ai)->semaphore) +static void +init_atomic_int (struct atomic_int *ai) +{ + sem_init (&ai->semaphore, 0, 0); +} +# endif +# if USE_NAMED_SEMAPHORE +struct atomic_int { + sem_t *semaphore; +}; +#define atomic_int_semaphore(ai) ((ai)->semaphore) +static void +init_atomic_int (struct atomic_int *ai) +{ + sem_t *s; + unsigned int count; + for (count = 0; ; count++) + { + char name[80]; + /* Use getpid() in the name, so that different processes running at the + same time will not interfere. Use ai in the name, so that different + atomic_int in the same process will not interfere. Use a count in + the name, so that even in the (unlikely) case that a semaphore with + the specified name already exists, we can try a different name. */ + sprintf (name, "test-lock-%lu-%p-%u", + (unsigned long) getpid (), ai, count); + s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); + if (s == SEM_FAILED) + { + if (errno == EEXIST) + /* Retry with a different name. */ + continue; + else + { + perror ("sem_open failed"); + abort (); + } + } + else + { + /* Try not to leave a semaphore hanging around on the file system + eternally, if we can avoid it. */ + sem_unlink (name); + break; + } + } + ai->semaphore = s; +} +# endif +static int +get_atomic_int_value (struct atomic_int *ai) +{ + if (sem_trywait (atomic_int_semaphore (ai)) == 0) + { + if (sem_post (atomic_int_semaphore (ai))) + abort (); + return 1; + } + else if (errno == EAGAIN) + return 0; + else + abort (); +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + if (new_value == 0) + /* It's already initialized with 0. */ + return; + /* To set the value 1: */ + if (sem_post (atomic_int_semaphore (ai))) + abort (); +} +#else +struct atomic_int { + gl_lock_define (, lock) + int value; +}; +static void +init_atomic_int (struct atomic_int *ai) +{ + gl_lock_init (ai->lock); +} +static int +get_atomic_int_value (struct atomic_int *ai) +{ + gl_lock_lock (ai->lock); + int ret = ai->value; + gl_lock_unlock (ai->lock); + return ret; +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + gl_lock_lock (ai->lock); + ai->value = new_value; + gl_lock_unlock (ai->lock); +} +#endif diff --git a/tests/test-lock.c b/tests/test-lock.c index 7325c89..08419b4 100644 --- a/tests/test-lock.c +++ b/tests/test-lock.c @@ -50,28 +50,6 @@ Uncomment this to see if the operating system has a fair scheduler. */ #define EXPLICIT_YIELD 1 -/* Whether to use 'volatile' on some variables that communicate information - between threads. If set to 0, a semaphore or a lock is used to protect - these variables. If set to 1, 'volatile' is used; this is theoretically - equivalent but can lead to much slower execution (e.g. 30x slower total - run time on a 40-core machine), because 'volatile' does not imply any - synchronization/communication between different CPUs. */ -#define USE_VOLATILE 0 - -#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H -/* Whether to use a semaphore to communicate information between threads. - If set to 0, a lock is used. If set to 1, a semaphore is used. - Uncomment this to reduce the dependencies of this test. */ -# define USE_SEMAPHORE 1 -/* Mac OS X provides only named semaphores (sem_open); its facility for - unnamed semaphores (sem_init) does not work. */ -# if defined __APPLE__ && defined __MACH__ -# define USE_NAMED_SEMAPHORE 1 -# else -# define USE_UNNAMED_SEMAPHORE 1 -# endif -#endif - /* Whether to print debugging messages. */ #define ENABLE_DEBUGGING 0 @@ -113,18 +91,14 @@ #include "glthread/thread.h" #include "glthread/yield.h" -#if USE_SEMAPHORE -# include -# include -# include -# include -#endif #if HAVE_DECL_ALARM # include # include #endif +#include "atomic-int-gnulib.h" + #if ENABLE_DEBUGGING # define dbgprintf printf #else @@ -137,132 +111,6 @@ # define yield() #endif -#if USE_VOLATILE -struct atomic_int { - volatile int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - return ai->value; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ai->value = new_value; -} -#elif USE_SEMAPHORE -/* This atomic_int implementation can only support the values 0 and 1. - It is initially 0 and can be set to 1 only once. */ -# if USE_UNNAMED_SEMAPHORE -struct atomic_int { - sem_t semaphore; -}; -#define atomic_int_semaphore(ai) (&(ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_init (&ai->semaphore, 0, 0); -} -# endif -# if USE_NAMED_SEMAPHORE -struct atomic_int { - sem_t *semaphore; -}; -#define atomic_int_semaphore(ai) ((ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_t *s; - unsigned int count; - for (count = 0; ; count++) - { - char name[80]; - /* Use getpid() in the name, so that different processes running at the - same time will not interfere. Use ai in the name, so that different - atomic_int in the same process will not interfere. Use a count in - the name, so that even in the (unlikely) case that a semaphore with - the specified name already exists, we can try a different name. */ - sprintf (name, "test-lock-%lu-%p-%u", - (unsigned long) getpid (), ai, count); - s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); - if (s == SEM_FAILED) - { - if (errno == EEXIST) - /* Retry with a different name. */ - continue; - else - { - perror ("sem_open failed"); - abort (); - } - } - else - { - /* Try not to leave a semaphore hanging around on the file system - eternally, if we can avoid it. */ - sem_unlink (name); - break; - } - } - ai->semaphore = s; -} -# endif -static int -get_atomic_int_value (struct atomic_int *ai) -{ - if (sem_trywait (atomic_int_semaphore (ai)) == 0) - { - if (sem_post (atomic_int_semaphore (ai))) - abort (); - return 1; - } - else if (errno == EAGAIN) - return 0; - else - abort (); -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - if (new_value == 0) - /* It's already initialized with 0. */ - return; - /* To set the value 1: */ - if (sem_post (atomic_int_semaphore (ai))) - abort (); -} -#else -struct atomic_int { - gl_lock_define (, lock) - int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ - gl_lock_init (ai->lock); -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - gl_lock_lock (ai->lock); - int ret = ai->value; - gl_lock_unlock (ai->lock); - return ret; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - gl_lock_lock (ai->lock); - ai->value = new_value; - gl_lock_unlock (ai->lock); -} -#endif - #define ACCOUNT_COUNT 4 static int account[ACCOUNT_COUNT]; -- 2.7.4 --nextPart3762119.ruPitNfY6I Content-Disposition: attachment; filename="0002-tests-Refactor.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0002-tests-Refactor.patch" >From b151d099fbfedb43161daf3112ec432456f52941 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 1 Jul 2020 22:06:13 +0200 Subject: [PATCH 2/4] tests: Refactor. * tests/atomic-int-isoc.h: New file, extracted from tests/test-mtx.c. * tests/test-mtx.c: Include it. Remove the corresponding code. * modules/mtx-tests (Files): Add tests/atomic-int-isoc.h. --- ChangeLog | 7 ++ modules/mtx-tests | 1 + tests/atomic-int-isoc.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/test-mtx.c | 156 +------------------------------------------ 4 files changed, 182 insertions(+), 155 deletions(-) create mode 100644 tests/atomic-int-isoc.h diff --git a/ChangeLog b/ChangeLog index d6c59e2..6b228f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ 2020-07-01 Bruno Haible tests: Refactor. + * tests/atomic-int-isoc.h: New file, extracted from tests/test-mtx.c. + * tests/test-mtx.c: Include it. Remove the corresponding code. + * modules/mtx-tests (Files): Add tests/atomic-int-isoc.h. + +2020-07-01 Bruno Haible + + tests: Refactor. * tests/atomic-int-gnulib.h: New file, extracted from tests/test-lock.c. * tests/test-lock.c: Include it. Remove the corresponding code. * modules/lock-tests (Files): Add tests/atomic-int-gnulib.h. diff --git a/modules/mtx-tests b/modules/mtx-tests index 7714ebc..5231062 100644 --- a/modules/mtx-tests +++ b/modules/mtx-tests @@ -1,6 +1,7 @@ Files: tests/test-mtx.c tests/test-call_once.c +tests/atomic-int-isoc.h tests/macros.h Depends-on: diff --git a/tests/atomic-int-isoc.h b/tests/atomic-int-isoc.h new file mode 100644 index 0000000..c4e57e9 --- /dev/null +++ b/tests/atomic-int-isoc.h @@ -0,0 +1,173 @@ +/* Atomic integers. Useful for testing multithreaded locking primitives. + Copyright (C) 2005, 2008-2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +/* Whether to use 'volatile' on some variables that communicate information + between threads. If set to 0, a semaphore or a lock is used to protect + these variables. If set to 1, 'volatile' is used; this is theoretically + equivalent but can lead to much slower execution (e.g. 30x slower total + run time on a 40-core machine), because 'volatile' does not imply any + synchronization/communication between different CPUs. */ +#define USE_VOLATILE 0 + +#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H +/* Whether to use a semaphore to communicate information between threads. + If set to 0, a lock is used. If set to 1, a semaphore is used. + Uncomment this to reduce the dependencies of this test. */ +# define USE_SEMAPHORE 1 +/* Mac OS X provides only named semaphores (sem_open); its facility for + unnamed semaphores (sem_init) does not work. */ +# if defined __APPLE__ && defined __MACH__ +# define USE_NAMED_SEMAPHORE 1 +# else +# define USE_UNNAMED_SEMAPHORE 1 +# endif +#endif + + +#if USE_SEMAPHORE +# include +# include +# include +# include +#endif + + +#if USE_VOLATILE +struct atomic_int { + volatile int value; +}; +static void +init_atomic_int (struct atomic_int *ai) +{ +} +static int +get_atomic_int_value (struct atomic_int *ai) +{ + return ai->value; +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + ai->value = new_value; +} +#elif USE_SEMAPHORE +/* This atomic_int implementation can only support the values 0 and 1. + It is initially 0 and can be set to 1 only once. */ +# if USE_UNNAMED_SEMAPHORE +struct atomic_int { + sem_t semaphore; +}; +#define atomic_int_semaphore(ai) (&(ai)->semaphore) +static void +init_atomic_int (struct atomic_int *ai) +{ + sem_init (&ai->semaphore, 0, 0); +} +# endif +# if USE_NAMED_SEMAPHORE +struct atomic_int { + sem_t *semaphore; +}; +#define atomic_int_semaphore(ai) ((ai)->semaphore) +static void +init_atomic_int (struct atomic_int *ai) +{ + sem_t *s; + unsigned int count; + for (count = 0; ; count++) + { + char name[80]; + /* Use getpid() in the name, so that different processes running at the + same time will not interfere. Use ai in the name, so that different + atomic_int in the same process will not interfere. Use a count in + the name, so that even in the (unlikely) case that a semaphore with + the specified name already exists, we can try a different name. */ + sprintf (name, "test-lock-%lu-%p-%u", + (unsigned long) getpid (), ai, count); + s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); + if (s == SEM_FAILED) + { + if (errno == EEXIST) + /* Retry with a different name. */ + continue; + else + { + perror ("sem_open failed"); + abort (); + } + } + else + { + /* Try not to leave a semaphore hanging around on the file system + eternally, if we can avoid it. */ + sem_unlink (name); + break; + } + } + ai->semaphore = s; +} +# endif +static int +get_atomic_int_value (struct atomic_int *ai) +{ + if (sem_trywait (atomic_int_semaphore (ai)) == 0) + { + if (sem_post (atomic_int_semaphore (ai))) + abort (); + return 1; + } + else if (errno == EAGAIN) + return 0; + else + abort (); +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + if (new_value == 0) + /* It's already initialized with 0. */ + return; + /* To set the value 1: */ + if (sem_post (atomic_int_semaphore (ai))) + abort (); +} +#else +struct atomic_int { + mtx_t lock; + int value; +}; +static void +init_atomic_int (struct atomic_int *ai) +{ + ASSERT (mtx_init (&ai->lock, mtx_plain) == thrd_success); +} +static int +get_atomic_int_value (struct atomic_int *ai) +{ + ASSERT (mtx_lock (&ai->lock) == thrd_success); + int ret = ai->value; + ASSERT (mtx_unlock (&ai->lock) == thrd_success); + return ret; +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + ASSERT (mtx_lock (&ai->lock) == thrd_success); + ai->value = new_value; + ASSERT (mtx_unlock (&ai->lock) == thrd_success); +} +#endif diff --git a/tests/test-mtx.c b/tests/test-mtx.c index cbd6fd4..54c4187 100644 --- a/tests/test-mtx.c +++ b/tests/test-mtx.c @@ -34,28 +34,6 @@ Uncomment this to see if the operating system has a fair scheduler. */ #define EXPLICIT_YIELD 1 -/* Whether to use 'volatile' on some variables that communicate information - between threads. If set to 0, a semaphore or a lock is used to protect - these variables. If set to 1, 'volatile' is used; this is theoretically - equivalent but can lead to much slower execution (e.g. 30x slower total - run time on a 40-core machine), because 'volatile' does not imply any - synchronization/communication between different CPUs. */ -#define USE_VOLATILE 0 - -#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H -/* Whether to use a semaphore to communicate information between threads. - If set to 0, a lock is used. If set to 1, a semaphore is used. - Uncomment this to reduce the dependencies of this test. */ -# define USE_SEMAPHORE 1 -/* Mac OS X provides only named semaphores (sem_open); its facility for - unnamed semaphores (sem_init) does not work. */ -# if defined __APPLE__ && defined __MACH__ -# define USE_NAMED_SEMAPHORE 1 -# else -# define USE_UNNAMED_SEMAPHORE 1 -# endif -#endif - /* Whether to print debugging messages. */ #define ENABLE_DEBUGGING 0 @@ -75,19 +53,13 @@ #include "glthread/lock.h" -#if USE_SEMAPHORE -# include -# include -# include -# include -#endif - #if HAVE_DECL_ALARM # include # include #endif #include "macros.h" +#include "atomic-int-isoc.h" #if ENABLE_DEBUGGING # define dbgprintf printf @@ -101,132 +73,6 @@ # define yield() #endif -#if USE_VOLATILE -struct atomic_int { - volatile int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - return ai->value; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ai->value = new_value; -} -#elif USE_SEMAPHORE -/* This atomic_int implementation can only support the values 0 and 1. - It is initially 0 and can be set to 1 only once. */ -# if USE_UNNAMED_SEMAPHORE -struct atomic_int { - sem_t semaphore; -}; -#define atomic_int_semaphore(ai) (&(ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_init (&ai->semaphore, 0, 0); -} -# endif -# if USE_NAMED_SEMAPHORE -struct atomic_int { - sem_t *semaphore; -}; -#define atomic_int_semaphore(ai) ((ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_t *s; - unsigned int count; - for (count = 0; ; count++) - { - char name[80]; - /* Use getpid() in the name, so that different processes running at the - same time will not interfere. Use ai in the name, so that different - atomic_int in the same process will not interfere. Use a count in - the name, so that even in the (unlikely) case that a semaphore with - the specified name already exists, we can try a different name. */ - sprintf (name, "test-lock-%lu-%p-%u", - (unsigned long) getpid (), ai, count); - s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); - if (s == SEM_FAILED) - { - if (errno == EEXIST) - /* Retry with a different name. */ - continue; - else - { - perror ("sem_open failed"); - abort (); - } - } - else - { - /* Try not to leave a semaphore hanging around on the file system - eternally, if we can avoid it. */ - sem_unlink (name); - break; - } - } - ai->semaphore = s; -} -# endif -static int -get_atomic_int_value (struct atomic_int *ai) -{ - if (sem_trywait (atomic_int_semaphore (ai)) == 0) - { - if (sem_post (atomic_int_semaphore (ai))) - abort (); - return 1; - } - else if (errno == EAGAIN) - return 0; - else - abort (); -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - if (new_value == 0) - /* It's already initialized with 0. */ - return; - /* To set the value 1: */ - if (sem_post (atomic_int_semaphore (ai))) - abort (); -} -#else -struct atomic_int { - mtx_t lock; - int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ - ASSERT (mtx_init (&ai->lock, mtx_plain) == thrd_success); -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - ASSERT (mtx_lock (&ai->lock) == thrd_success); - int ret = ai->value; - ASSERT (mtx_unlock (&ai->lock) == thrd_success); - return ret; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ASSERT (mtx_lock (&ai->lock) == thrd_success); - ai->value = new_value; - ASSERT (mtx_unlock (&ai->lock) == thrd_success); -} -#endif - /* Returns a reference to the current thread as a pointer, for debugging. */ #if defined __MVS__ /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field. -- 2.7.4 --nextPart3762119.ruPitNfY6I Content-Disposition: attachment; filename="0003-tests-Reduce-code-duplication.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0003-tests-Reduce-code-duplication.patch" >From 6b9216ed0b43b2777d8d12f865e32edb5b30d945 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 1 Jul 2020 22:06:27 +0200 Subject: [PATCH 3/4] tests: Reduce code duplication. * tests/atomic-int-posix.h: New file, extracted from tests/test-pthread-mutex.c. * tests/test-pthread-mutex.c: Include it. Remove the corresponding code. * tests/test-pthread-rwlock.c: Likewise. * modules/pthread-mutex-tests (Files): Add tests/atomic-int-posix.h. * modules/pthread-rwlock-tests (Files): Likewise. --- ChangeLog | 10 +++ modules/pthread-mutex-tests | 1 + modules/pthread-rwlock-tests | 1 + tests/atomic-int-posix.h | 178 +++++++++++++++++++++++++++++++++++++++++++ tests/test-pthread-mutex.c | 161 +------------------------------------- tests/test-pthread-rwlock.c | 161 +------------------------------------- 6 files changed, 192 insertions(+), 320 deletions(-) create mode 100644 tests/atomic-int-posix.h diff --git a/ChangeLog b/ChangeLog index 6b228f0..cd09023 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2020-07-01 Bruno Haible + tests: Reduce code duplication. + * tests/atomic-int-posix.h: New file, extracted from + tests/test-pthread-mutex.c. + * tests/test-pthread-mutex.c: Include it. Remove the corresponding code. + * tests/test-pthread-rwlock.c: Likewise. + * modules/pthread-mutex-tests (Files): Add tests/atomic-int-posix.h. + * modules/pthread-rwlock-tests (Files): Likewise. + +2020-07-01 Bruno Haible + tests: Refactor. * tests/atomic-int-isoc.h: New file, extracted from tests/test-mtx.c. * tests/test-mtx.c: Include it. Remove the corresponding code. diff --git a/modules/pthread-mutex-tests b/modules/pthread-mutex-tests index 12d386e..c419dcc 100644 --- a/modules/pthread-mutex-tests +++ b/modules/pthread-mutex-tests @@ -1,5 +1,6 @@ Files: tests/test-pthread-mutex.c +tests/atomic-int-posix.h tests/macros.h Depends-on: diff --git a/modules/pthread-rwlock-tests b/modules/pthread-rwlock-tests index 340ebf0..594f6b6 100644 --- a/modules/pthread-rwlock-tests +++ b/modules/pthread-rwlock-tests @@ -1,5 +1,6 @@ Files: tests/test-pthread-rwlock.c +tests/atomic-int-posix.h tests/macros.h Depends-on: diff --git a/tests/atomic-int-posix.h b/tests/atomic-int-posix.h new file mode 100644 index 0000000..dac797e --- /dev/null +++ b/tests/atomic-int-posix.h @@ -0,0 +1,178 @@ +/* Atomic integers. Useful for testing multithreaded locking primitives. + Copyright (C) 2005, 2008-2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + +/* Whether to use 'volatile' on some variables that communicate information + between threads. If set to 0, a semaphore or a lock is used to protect + these variables. If set to 1, 'volatile' is used; this is theoretically + equivalent but can lead to much slower execution (e.g. 30x slower total + run time on a 40-core machine), because 'volatile' does not imply any + synchronization/communication between different CPUs. */ +#define USE_VOLATILE 0 + +#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H +/* Whether to use a semaphore to communicate information between threads. + If set to 0, a lock is used. If set to 1, a semaphore is used. + Uncomment this to reduce the dependencies of this test. */ +# define USE_SEMAPHORE 1 +/* Mac OS X provides only named semaphores (sem_open); its facility for + unnamed semaphores (sem_init) does not work. */ +# if defined __APPLE__ && defined __MACH__ +# define USE_NAMED_SEMAPHORE 1 +# else +# define USE_UNNAMED_SEMAPHORE 1 +# endif +#endif + + +#if USE_SEMAPHORE +# include +# include +# include +# include +#endif + + +#if USE_VOLATILE +struct atomic_int { + volatile int value; +}; +static void +init_atomic_int (struct atomic_int *ai) +{ +} +static int +get_atomic_int_value (struct atomic_int *ai) +{ + return ai->value; +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + ai->value = new_value; +} +#elif USE_SEMAPHORE +/* This atomic_int implementation can only support the values 0 and 1. + It is initially 0 and can be set to 1 only once. */ +# if USE_UNNAMED_SEMAPHORE +struct atomic_int { + sem_t semaphore; +}; +#define atomic_int_semaphore(ai) (&(ai)->semaphore) +static void +init_atomic_int (struct atomic_int *ai) +{ + sem_init (&ai->semaphore, 0, 0); +} +# endif +# if USE_NAMED_SEMAPHORE +struct atomic_int { + sem_t *semaphore; +}; +#define atomic_int_semaphore(ai) ((ai)->semaphore) +static void +init_atomic_int (struct atomic_int *ai) +{ + sem_t *s; + unsigned int count; + for (count = 0; ; count++) + { + char name[80]; + /* Use getpid() in the name, so that different processes running at the + same time will not interfere. Use ai in the name, so that different + atomic_int in the same process will not interfere. Use a count in + the name, so that even in the (unlikely) case that a semaphore with + the specified name already exists, we can try a different name. */ + sprintf (name, "test-lock-%lu-%p-%u", + (unsigned long) getpid (), ai, count); + s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); + if (s == SEM_FAILED) + { + if (errno == EEXIST) + /* Retry with a different name. */ + continue; + else + { + perror ("sem_open failed"); + abort (); + } + } + else + { + /* Try not to leave a semaphore hanging around on the file system + eternally, if we can avoid it. */ + sem_unlink (name); + break; + } + } + ai->semaphore = s; +} +# endif +static int +get_atomic_int_value (struct atomic_int *ai) +{ + if (sem_trywait (atomic_int_semaphore (ai)) == 0) + { + if (sem_post (atomic_int_semaphore (ai))) + abort (); + return 1; + } + else if (errno == EAGAIN) + return 0; + else + abort (); +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + if (new_value == 0) + /* It's already initialized with 0. */ + return; + /* To set the value 1: */ + if (sem_post (atomic_int_semaphore (ai))) + abort (); +} +#else +struct atomic_int { + pthread_mutex_t lock; + int value; +}; +static void +init_atomic_int (struct atomic_int *ai) +{ + pthread_mutexattr_t attr; + + ASSERT (pthread_mutexattr_init (&attr) == 0); + ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0); + ASSERT (pthread_mutex_init (&ai->lock, &attr) == 0); + ASSERT (pthread_mutexattr_destroy (&attr) == 0); +} +static int +get_atomic_int_value (struct atomic_int *ai) +{ + ASSERT (pthread_mutex_lock (&ai->lock) == 0); + int ret = ai->value; + ASSERT (pthread_mutex_unlock (&ai->lock) == 0); + return ret; +} +static void +set_atomic_int_value (struct atomic_int *ai, int new_value) +{ + ASSERT (pthread_mutex_lock (&ai->lock) == 0); + ai->value = new_value; + ASSERT (pthread_mutex_unlock (&ai->lock) == 0); +} +#endif diff --git a/tests/test-pthread-mutex.c b/tests/test-pthread-mutex.c index 55eeb88..b746e57 100644 --- a/tests/test-pthread-mutex.c +++ b/tests/test-pthread-mutex.c @@ -35,28 +35,6 @@ Uncomment this to see if the operating system has a fair scheduler. */ #define EXPLICIT_YIELD 1 -/* Whether to use 'volatile' on some variables that communicate information - between threads. If set to 0, a semaphore or a lock is used to protect - these variables. If set to 1, 'volatile' is used; this is theoretically - equivalent but can lead to much slower execution (e.g. 30x slower total - run time on a 40-core machine), because 'volatile' does not imply any - synchronization/communication between different CPUs. */ -#define USE_VOLATILE 0 - -#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H -/* Whether to use a semaphore to communicate information between threads. - If set to 0, a lock is used. If set to 1, a semaphore is used. - Uncomment this to reduce the dependencies of this test. */ -# define USE_SEMAPHORE 1 -/* Mac OS X provides only named semaphores (sem_open); its facility for - unnamed semaphores (sem_init) does not work. */ -# if defined __APPLE__ && defined __MACH__ -# define USE_NAMED_SEMAPHORE 1 -# else -# define USE_UNNAMED_SEMAPHORE 1 -# endif -#endif - /* Whether to print debugging messages. */ #define ENABLE_DEBUGGING 0 @@ -78,19 +56,13 @@ # include #endif -#if USE_SEMAPHORE -# include -# include -# include -# include -#endif - #if HAVE_DECL_ALARM # include # include #endif #include "macros.h" +#include "atomic-int-posix.h" #if ENABLE_DEBUGGING # define dbgprintf printf @@ -104,137 +76,6 @@ # define yield() #endif -#if USE_VOLATILE -struct atomic_int { - volatile int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - return ai->value; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ai->value = new_value; -} -#elif USE_SEMAPHORE -/* This atomic_int implementation can only support the values 0 and 1. - It is initially 0 and can be set to 1 only once. */ -# if USE_UNNAMED_SEMAPHORE -struct atomic_int { - sem_t semaphore; -}; -#define atomic_int_semaphore(ai) (&(ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_init (&ai->semaphore, 0, 0); -} -# endif -# if USE_NAMED_SEMAPHORE -struct atomic_int { - sem_t *semaphore; -}; -#define atomic_int_semaphore(ai) ((ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_t *s; - unsigned int count; - for (count = 0; ; count++) - { - char name[80]; - /* Use getpid() in the name, so that different processes running at the - same time will not interfere. Use ai in the name, so that different - atomic_int in the same process will not interfere. Use a count in - the name, so that even in the (unlikely) case that a semaphore with - the specified name already exists, we can try a different name. */ - sprintf (name, "test-lock-%lu-%p-%u", - (unsigned long) getpid (), ai, count); - s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); - if (s == SEM_FAILED) - { - if (errno == EEXIST) - /* Retry with a different name. */ - continue; - else - { - perror ("sem_open failed"); - abort (); - } - } - else - { - /* Try not to leave a semaphore hanging around on the file system - eternally, if we can avoid it. */ - sem_unlink (name); - break; - } - } - ai->semaphore = s; -} -# endif -static int -get_atomic_int_value (struct atomic_int *ai) -{ - if (sem_trywait (atomic_int_semaphore (ai)) == 0) - { - if (sem_post (atomic_int_semaphore (ai))) - abort (); - return 1; - } - else if (errno == EAGAIN) - return 0; - else - abort (); -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - if (new_value == 0) - /* It's already initialized with 0. */ - return; - /* To set the value 1: */ - if (sem_post (atomic_int_semaphore (ai))) - abort (); -} -#else -struct atomic_int { - pthread_mutex_t lock; - int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ - pthread_mutexattr_t attr; - - ASSERT (pthread_mutexattr_init (&attr) == 0); - ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0); - ASSERT (pthread_mutex_init (&ai->lock, &attr) == 0); - ASSERT (pthread_mutexattr_destroy (&attr) == 0); -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - ASSERT (pthread_mutex_lock (&ai->lock) == 0); - int ret = ai->value; - ASSERT (pthread_mutex_unlock (&ai->lock) == 0); - return ret; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ASSERT (pthread_mutex_lock (&ai->lock) == 0); - ai->value = new_value; - ASSERT (pthread_mutex_unlock (&ai->lock) == 0); -} -#endif - /* Returns a reference to the current thread as a pointer, for debugging. */ #if defined __MVS__ /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field. diff --git a/tests/test-pthread-rwlock.c b/tests/test-pthread-rwlock.c index 9f15acb..7b8d013 100644 --- a/tests/test-pthread-rwlock.c +++ b/tests/test-pthread-rwlock.c @@ -29,28 +29,6 @@ Uncomment this to see if the operating system has a fair scheduler. */ #define EXPLICIT_YIELD 1 -/* Whether to use 'volatile' on some variables that communicate information - between threads. If set to 0, a semaphore or a lock is used to protect - these variables. If set to 1, 'volatile' is used; this is theoretically - equivalent but can lead to much slower execution (e.g. 30x slower total - run time on a 40-core machine), because 'volatile' does not imply any - synchronization/communication between different CPUs. */ -#define USE_VOLATILE 0 - -#if USE_POSIX_THREADS && HAVE_SEMAPHORE_H -/* Whether to use a semaphore to communicate information between threads. - If set to 0, a lock is used. If set to 1, a semaphore is used. - Uncomment this to reduce the dependencies of this test. */ -# define USE_SEMAPHORE 1 -/* Mac OS X provides only named semaphores (sem_open); its facility for - unnamed semaphores (sem_init) does not work. */ -# if defined __APPLE__ && defined __MACH__ -# define USE_NAMED_SEMAPHORE 1 -# else -# define USE_UNNAMED_SEMAPHORE 1 -# endif -#endif - /* Whether to print debugging messages. */ #define ENABLE_DEBUGGING 0 @@ -72,19 +50,13 @@ # include #endif -#if USE_SEMAPHORE -# include -# include -# include -# include -#endif - #if HAVE_DECL_ALARM # include # include #endif #include "macros.h" +#include "atomic-int-posix.h" #if ENABLE_DEBUGGING # define dbgprintf printf @@ -98,137 +70,6 @@ # define yield() #endif -#if USE_VOLATILE -struct atomic_int { - volatile int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - return ai->value; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ai->value = new_value; -} -#elif USE_SEMAPHORE -/* This atomic_int implementation can only support the values 0 and 1. - It is initially 0 and can be set to 1 only once. */ -# if USE_UNNAMED_SEMAPHORE -struct atomic_int { - sem_t semaphore; -}; -#define atomic_int_semaphore(ai) (&(ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_init (&ai->semaphore, 0, 0); -} -# endif -# if USE_NAMED_SEMAPHORE -struct atomic_int { - sem_t *semaphore; -}; -#define atomic_int_semaphore(ai) ((ai)->semaphore) -static void -init_atomic_int (struct atomic_int *ai) -{ - sem_t *s; - unsigned int count; - for (count = 0; ; count++) - { - char name[80]; - /* Use getpid() in the name, so that different processes running at the - same time will not interfere. Use ai in the name, so that different - atomic_int in the same process will not interfere. Use a count in - the name, so that even in the (unlikely) case that a semaphore with - the specified name already exists, we can try a different name. */ - sprintf (name, "test-lock-%lu-%p-%u", - (unsigned long) getpid (), ai, count); - s = sem_open (name, O_CREAT | O_EXCL, 0600, 0); - if (s == SEM_FAILED) - { - if (errno == EEXIST) - /* Retry with a different name. */ - continue; - else - { - perror ("sem_open failed"); - abort (); - } - } - else - { - /* Try not to leave a semaphore hanging around on the file system - eternally, if we can avoid it. */ - sem_unlink (name); - break; - } - } - ai->semaphore = s; -} -# endif -static int -get_atomic_int_value (struct atomic_int *ai) -{ - if (sem_trywait (atomic_int_semaphore (ai)) == 0) - { - if (sem_post (atomic_int_semaphore (ai))) - abort (); - return 1; - } - else if (errno == EAGAIN) - return 0; - else - abort (); -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - if (new_value == 0) - /* It's already initialized with 0. */ - return; - /* To set the value 1: */ - if (sem_post (atomic_int_semaphore (ai))) - abort (); -} -#else -struct atomic_int { - pthread_mutex_t lock; - int value; -}; -static void -init_atomic_int (struct atomic_int *ai) -{ - pthread_mutexattr_t attr; - - ASSERT (pthread_mutexattr_init (&attr) == 0); - ASSERT (pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL) == 0); - ASSERT (pthread_mutex_init (&ai->lock, &attr) == 0); - ASSERT (pthread_mutexattr_destroy (&attr) == 0); -} -static int -get_atomic_int_value (struct atomic_int *ai) -{ - ASSERT (pthread_mutex_lock (&ai->lock) == 0); - int ret = ai->value; - ASSERT (pthread_mutex_unlock (&ai->lock) == 0); - return ret; -} -static void -set_atomic_int_value (struct atomic_int *ai, int new_value) -{ - ASSERT (pthread_mutex_lock (&ai->lock) == 0); - ai->value = new_value; - ASSERT (pthread_mutex_unlock (&ai->lock) == 0); -} -#endif - /* Returns a reference to the current thread as a pointer, for debugging. */ #if defined __MVS__ /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field. -- 2.7.4 --nextPart3762119.ruPitNfY6I Content-Disposition: attachment; filename="0004-pthread-spin-Add-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="UTF-8"; name="0004-pthread-spin-Add-tests.patch" >From ab0284709c3fafeb51679a309d61b37d7d52dc1d Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 1 Jul 2020 22:06:45 +0200 Subject: [PATCH 4/4] pthread-spin: Add tests. * tests/test-pthread-spin.c: New file, based on tests/test-lock.c. * modules/pthread-spin-tests: New file. --- ChangeLog | 6 ++ modules/pthread-spin-tests | 20 ++++ tests/test-pthread-spin.c | 231 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 modules/pthread-spin-tests create mode 100644 tests/test-pthread-spin.c diff --git a/ChangeLog b/ChangeLog index cd09023..86c32ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-07-01 Bruno Haible + pthread-spin: Add tests. + * tests/test-pthread-spin.c: New file, based on tests/test-lock.c. + * modules/pthread-spin-tests: New file. + +2020-07-01 Bruno Haible + tests: Reduce code duplication. * tests/atomic-int-posix.h: New file, extracted from tests/test-pthread-mutex.c. diff --git a/modules/pthread-spin-tests b/modules/pthread-spin-tests new file mode 100644 index 0000000..aafe8c7 --- /dev/null +++ b/modules/pthread-spin-tests @@ -0,0 +1,20 @@ +Files: +tests/test-pthread-spin.c +tests/atomic-int-posix.h +tests/macros.h +m4/semaphore.m4 + +Depends-on: +pthread-thread +pthread-mutex +sched_yield + +configure.ac: +AC_CHECK_HEADERS_ONCE([semaphore.h]) +AC_CHECK_DECLS_ONCE([alarm]) +AC_REQUIRE([gl_SEMAPHORE]) + +Makefile.am: +TESTS += test-pthread-spin +check_PROGRAMS += test-pthread-spin +test_pthread_spin_LDADD = $(LDADD) @LIBPMULTITHREAD@ @LIB_SCHED_YIELD@ @LIB_SEMAPHORE@ diff --git a/tests/test-pthread-spin.c b/tests/test-pthread-spin.c new file mode 100644 index 0000000..aec8a96 --- /dev/null +++ b/tests/test-pthread-spin.c @@ -0,0 +1,231 @@ +/* Test of POSIX spin locks. + Copyright (C) 2005, 2008-2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2005. */ + +#include + +#if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS + +/* Whether to enable locking. + Uncomment this to get a test program without locking, to verify that + it crashes. */ +#define ENABLE_LOCKING 1 + +/* Whether to help the scheduler through explicit sched_yield(). + Uncomment this to see if the operating system has a fair scheduler. */ +#define EXPLICIT_YIELD 1 + +/* Whether to print debugging messages. */ +#define ENABLE_DEBUGGING 0 + +/* Number of simultaneous threads. */ +#define THREAD_COUNT 10 + +/* Number of operations performed in each thread. */ +#define REPEAT_COUNT 50000 + +#include +#include +#include +#include +#include + +#if EXPLICIT_YIELD +# include +#endif + +#if HAVE_DECL_ALARM +# include +# include +#endif + +#include "macros.h" +#include "atomic-int-posix.h" + +#if ENABLE_DEBUGGING +# define dbgprintf printf +#else +# define dbgprintf if (0) printf +#endif + +#if EXPLICIT_YIELD +# define yield() sched_yield () +#else +# define yield() +#endif + +/* Returns a reference to the current thread as a pointer, for debugging. */ +#if defined __MVS__ + /* On IBM z/OS, pthread_t is a struct with an 8-byte '__' field. + The first three bytes of this field appear to uniquely identify a + pthread_t, though not necessarily representing a pointer. */ +# define pthread_self_pointer() (*((void **) pthread_self ().__)) +#else +# define pthread_self_pointer() ((void *) (uintptr_t) pthread_self ()) +#endif + +#define ACCOUNT_COUNT 4 + +static int account[ACCOUNT_COUNT]; + +static int +random_account (void) +{ + return ((unsigned int) rand () >> 3) % ACCOUNT_COUNT; +} + +static void +check_accounts (void) +{ + int i, sum; + + sum = 0; + for (i = 0; i < ACCOUNT_COUNT; i++) + sum += account[i]; + if (sum != ACCOUNT_COUNT * 1000) + abort (); +} + + +/* ------------------- Test use like normal locks ------------------- */ + +/* Test normal locks by having several bank accounts and several threads + which shuffle around money between the accounts and another thread + checking that all the money is still there. */ + +static pthread_spinlock_t my_lock; + +static void * +lock_mutator_thread (void *arg) +{ + int repeat; + + for (repeat = REPEAT_COUNT; repeat > 0; repeat--) + { + int i1, i2, value; + + dbgprintf ("Mutator %p before lock\n", pthread_self_pointer ()); + ASSERT (pthread_spin_lock (&my_lock) == 0); + dbgprintf ("Mutator %p after lock\n", pthread_self_pointer ()); + + i1 = random_account (); + i2 = random_account (); + value = ((unsigned int) rand () >> 3) % 10; + account[i1] += value; + account[i2] -= value; + + dbgprintf ("Mutator %p before unlock\n", pthread_self_pointer ()); + ASSERT (pthread_spin_unlock (&my_lock) == 0); + dbgprintf ("Mutator %p after unlock\n", pthread_self_pointer ()); + + dbgprintf ("Mutator %p before check lock\n", pthread_self_pointer ()); + ASSERT (pthread_spin_lock (&my_lock) == 0); + check_accounts (); + ASSERT (pthread_spin_unlock (&my_lock) == 0); + dbgprintf ("Mutator %p after check unlock\n", pthread_self_pointer ()); + + yield (); + } + + dbgprintf ("Mutator %p dying.\n", pthread_self_pointer ()); + return NULL; +} + +static struct atomic_int lock_checker_done; + +static void * +lock_checker_thread (void *arg) +{ + while (get_atomic_int_value (&lock_checker_done) == 0) + { + dbgprintf ("Checker %p before check lock\n", pthread_self_pointer ()); + ASSERT (pthread_spin_lock (&my_lock) == 0); + check_accounts (); + ASSERT (pthread_spin_unlock (&my_lock) == 0); + dbgprintf ("Checker %p after check unlock\n", pthread_self_pointer ()); + + yield (); + } + + dbgprintf ("Checker %p dying.\n", pthread_self_pointer ()); + return NULL; +} + +static void +test_pthread_spin (void) +{ + int i; + pthread_t checkerthread; + pthread_t threads[THREAD_COUNT]; + + /* Initialization. */ + for (i = 0; i < ACCOUNT_COUNT; i++) + account[i] = 1000; + init_atomic_int (&lock_checker_done); + set_atomic_int_value (&lock_checker_done, 0); + + /* Spawn the threads. */ + ASSERT (pthread_create (&checkerthread, NULL, lock_checker_thread, NULL) + == 0); + for (i = 0; i < THREAD_COUNT; i++) + ASSERT (pthread_create (&threads[i], NULL, lock_mutator_thread, NULL) == 0); + + /* Wait for the threads to terminate. */ + for (i = 0; i < THREAD_COUNT; i++) + ASSERT (pthread_join (threads[i], NULL) == 0); + set_atomic_int_value (&lock_checker_done, 1); + ASSERT (pthread_join (checkerthread, NULL) == 0); + check_accounts (); +} + + +/* -------------------------------------------------------------------------- */ + +int +main () +{ +#if HAVE_DECL_ALARM + /* Declare failure if test takes too long, by using default abort + caused by SIGALRM. */ + int alarm_value = 600; + signal (SIGALRM, SIG_DFL); + alarm (alarm_value); +#endif + + ASSERT (pthread_spin_init (&my_lock, 0) == 0); + + printf ("Starting test_pthread_spin ..."); fflush (stdout); + test_pthread_spin (); + printf (" OK\n"); fflush (stdout); + + return 0; +} + +#else + +/* No multithreading available. */ + +#include + +int +main () +{ + fputs ("Skipping test: multithreading not enabled\n", stderr); + return 77; +} + +#endif -- 2.7.4 --nextPart3762119.ruPitNfY6I--