From patchwork Wed Aug 17 12:54:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 660095 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3sDq2X5xCwz9ssP for ; Wed, 17 Aug 2016 22:55:16 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b=p6SE4wbH; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:to:subject:mime-version:content-type :content-transfer-encoding:message-id:from; q=dns; s=default; b= qjNz95DgMRigNwCvUumazgO62dUXtE8UhFd9GZq4nz3kok0h5hL9NZwIY+vspWMV Zzgoc/sDX67LiIqml8R/uyXHT4Df22PKXTxMv9xk4XO5o6RO1J+5I7sx7VmvQAec ooUH51Xqd2cHkz43Ozydx/CgDNu0IqnZ/aQ0uFT8yFs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:to:subject:mime-version:content-type :content-transfer-encoding:message-id:from; s=default; bh=I+JTLh +SnIMG0gupaXvGxIIuljo=; b=p6SE4wbHP8/0ezU+0aUwY93/JN1fHDC2qRZRaV DelAw+olmgIuj8R4n6k5UC601xwdrStR4ZAteMJjRR7bF8tYwBcQ3gvq2eegsSBG n8vQMBiVdPP6mxsXIYE+ISR3zpcc+IgXEZWzg/zvbxAUNpclXcUP6Rtp6EV4bhBf /kFd8= Received: (qmail 821 invoked by alias); 17 Aug 2016 12:55:09 -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 130764 invoked by uid 89); 17 Aug 2016 12:55:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.3 required=5.0 tests=BAYES_50, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=Used, 2210, 22, 10, UD:stdbool.h X-HELO: mx1.redhat.com Date: Wed, 17 Aug 2016 14:54:55 +0200 To: libc-alpha@sourceware.org Subject: [PATCH] nptl: Avoid expected SIGALRM in most tests [BZ #20432] User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Message-Id: <20160817125455.B3F11439942E2@oldenburg.str.redhat.com> From: fweimer@redhat.com (Florian Weimer) Before this change, several tests did not detect early deadlocks because they used SIGALRM as the expected signal, and they ran for the full default TIMEOUT seconds. This commit adds a new delayed_exit function to the test skeleton, along with several error-checking wrappers to pthread functions. Additional error checking is introduced into several tests. 2016-08-17 Florian Weimer [BZ #20432] Avoid expected SIGALRM signals. * test-skeleton.c (xpthread_sigmask, xpthread_mutex_lock) (xpthread_spin_lock, xpthread_cond_wait, xpthread_barrier_wait) (xpthread_create, xpthread_detach, xpthread_join) (delayed_exit_thread, delayed_exit): New functions. * nptl/tst-cond3 (EXPECTED_SIGNAL): Remove. (tf): Use xpthread_cond_wait. (do_test): Likewise. Replace alarm with delayed_exit. * nptl/tst-eintr1.c (EXPECTED_SIGNAL, TIMEOUT): Remove. (do_test): Call delayed_exit. Report failure. * nptl/tst-eintr2.c (EXPECTED_SIGNAL, TIMEOUT): Remove. (do_test): Call delayed_exit. * nptl/tst-eintr3.c (EXPECTED_SIGNAL, TIMEOUT): Remove. (do_test): Call delayed_exit. Use xpthread_join. Report error. * nptl/tst-eintr4.c (EXPECTED_SIGNAL, TIMEOUT): Remove. (do_test): Call delayed_exit. Use xpthread_barrier_wait. Report error. * nptl/tst-eintr5.c (EXPECTED_SIGNAL, TIMEOUT): Remove. (do_test): Call delayed_exit. Use xpthread_cond_wait. Report error. * nptl/tst-exit2.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit. * nptl/tst-exit3.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit. * nptl/tst-mutex6.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit instead of alarm. Use xpthread_mutex_lock. * nptl/tst-rwlock5.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit instead of alarm. Use xpthread_mutex_lock. * nptl/tst-sem2.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit instead of alarm. * nptl/tst-spin3.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit instead of alarm. Use xpthread_spin_lock. * nptl/tst-stdio1.c (EXPECTED_SIGNAL): Remove. (do_test): Call delayed_exit instead of alarm. Use xpthread_join. diff --git a/nptl/tst-cond3.c b/nptl/tst-cond3.c index ff904e4..724630f 100644 --- a/nptl/tst-cond3.c +++ b/nptl/tst-cond3.c @@ -22,6 +22,10 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" /* Note that this test requires more than the standard. It is required that there are no spurious wakeups if only more readers @@ -50,7 +54,8 @@ tf (void *arg) } /* This call should never return. */ - pthread_cond_wait (&cond, &mut); + xpthread_cond_wait (&cond, &mut); + puts ("error: pthread_cond_wait in tf returned"); /* We should never get here. */ exit (1); @@ -96,17 +101,11 @@ do_test (void) } } - /* Set an alarm for 1 second. The wrapper will expect this. */ - alarm (1); + delayed_exit (1); /* This call should never return. */ - pthread_cond_wait (&cond, &mut); + xpthread_cond_wait (&cond, &mut); - puts ("cond_wait returned"); + puts ("pthread_cond_wait in do_test returned"); return 1; } - - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-eintr1.c b/nptl/tst-eintr1.c index 11cd876..0946894 100644 --- a/nptl/tst-eintr1.c +++ b/nptl/tst-eintr1.c @@ -23,6 +23,11 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + #include "eintr.c" @@ -92,13 +97,8 @@ do_test (void) } } + delayed_exit (3); + /* This call must never return. */ (void) tf1 (NULL); - /* NOTREACHED */ - - return 0; + return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TIMEOUT 3 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-eintr2.c b/nptl/tst-eintr2.c index 7f50f4b..0ef6d30 100644 --- a/nptl/tst-eintr2.c +++ b/nptl/tst-eintr2.c @@ -24,6 +24,11 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + #include "eintr.c" @@ -103,6 +108,7 @@ do_test (void) exit (1); } + delayed_exit (3); /* This call must never return. */ e = pthread_mutex_lock (&m1); printf ("main: mutex_lock returned: %s\n", @@ -110,8 +116,3 @@ do_test (void) return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TIMEOUT 3 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-eintr3.c b/nptl/tst-eintr3.c index d2c32b9..f6b2ccf 100644 --- a/nptl/tst-eintr3.c +++ b/nptl/tst-eintr3.c @@ -23,6 +23,11 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + #include "eintr.c" @@ -56,16 +61,9 @@ do_test (void) exit (1); } + delayed_exit (1); /* This call must never return. */ - e = pthread_join (th, NULL); - - if (e == EINTR) - puts ("pthread_join returned with EINTR"); - - return 0; + xpthread_join (th); + puts ("error: pthread_join returned"); + return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TIMEOUT 1 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-eintr4.c b/nptl/tst-eintr4.c index 25fae34..f6d068f 100644 --- a/nptl/tst-eintr4.c +++ b/nptl/tst-eintr4.c @@ -23,6 +23,11 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + #include "eintr.c" @@ -40,16 +45,9 @@ do_test (void) exit (1); } + delayed_exit (1); /* This call must never return. */ - int e = pthread_barrier_wait (&b); - - if (e == EINTR) - puts ("pthread_join returned with EINTR"); - - return 0; + xpthread_barrier_wait (&b); + puts ("error: pthread_barrier_wait returned"); + return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TIMEOUT 1 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-eintr5.c b/nptl/tst-eintr5.c index be6731c..81f900e 100644 --- a/nptl/tst-eintr5.c +++ b/nptl/tst-eintr5.c @@ -24,6 +24,11 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + #include "eintr.c" @@ -66,15 +71,9 @@ do_test (void) exit (1); } + delayed_exit (3); /* This call must never return. */ - e = pthread_cond_wait (&c, &m); - printf ("main: cond_wait returned: %s\n", - strerror_r (e, buf, sizeof (buf))); - - return 0; + xpthread_cond_wait (&c, &m); + puts ("error: pthread_cond_wait returned"); + return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TIMEOUT 3 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-exit2.c b/nptl/tst-exit2.c index 3f5ff27..0b7a2ca 100644 --- a/nptl/tst-exit2.c +++ b/nptl/tst-exit2.c @@ -4,6 +4,10 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static void * tf (void *arg) @@ -28,13 +32,11 @@ do_test (void) return 1; } + delayed_exit (1); + /* Terminate only this thread. */ pthread_exit (NULL); /* NOTREACHED */ return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-exit3.c b/nptl/tst-exit3.c index da92c82..9481ed9 100644 --- a/nptl/tst-exit3.c +++ b/nptl/tst-exit3.c @@ -5,6 +5,10 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static pthread_barrier_t b; @@ -69,13 +73,11 @@ do_test (void) exit (1); } + delayed_exit (3); + /* Terminate only this thread. */ pthread_exit (NULL); /* NOTREACHED */ return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-mutex6.c b/nptl/tst-mutex6.c index 1940687..3e989d8 100644 --- a/nptl/tst-mutex6.c +++ b/nptl/tst-mutex6.c @@ -23,6 +23,11 @@ #include #include +#ifndef TEST_FUNCTION +static int do_test (void); +# define TEST_FUNCTION do_test () +#endif +#include "../test-skeleton.c" #ifndef ATTR pthread_mutexattr_t *attr; @@ -62,18 +67,10 @@ do_test (void) return 1; } - /* Set an alarm for 1 second. The wrapper will expect this. */ - alarm (1); - + delayed_exit (1); /* This call should never return. */ - pthread_mutex_lock (&m); + xpthread_mutex_lock (&m); puts ("2nd mutex_lock returned"); return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#ifndef TEST_FUNCTION -# define TEST_FUNCTION do_test () -#endif -#include "../test-skeleton.c" diff --git a/nptl/tst-rwlock5.c b/nptl/tst-rwlock5.c index b6c5d8a..20fb471 100644 --- a/nptl/tst-rwlock5.c +++ b/nptl/tst-rwlock5.c @@ -22,6 +22,10 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; static pthread_rwlock_t r; @@ -65,22 +69,16 @@ do_test (void) return 1; } - /* Set an alarm for 1 second. The wrapper will expect this. */ - alarm (1); - if (pthread_create (&th, NULL, tf, NULL) != 0) { puts ("create failed"); return 1; } + delayed_exit (1); /* This call should never return. */ - pthread_mutex_lock (&m); + xpthread_mutex_lock (&m); puts ("2nd mutex_lock returned"); return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-sem2.c b/nptl/tst-sem2.c index 301dde7..1f609fc 100644 --- a/nptl/tst-sem2.c +++ b/nptl/tst-sem2.c @@ -17,11 +17,16 @@ . */ #include +#include #include #include #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static int do_test (void) @@ -34,8 +39,7 @@ do_test (void) return 1; } - /* Set an alarm for 1 second. The wrapper will expect this. */ - alarm (1); + delayed_exit (1); if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) { @@ -47,7 +51,3 @@ do_test (void) puts ("wait succeeded"); return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-spin3.c b/nptl/tst-spin3.c index 8964ecc..6cb6f9d 100644 --- a/nptl/tst-spin3.c +++ b/nptl/tst-spin3.c @@ -21,6 +21,10 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static int do_test (void) @@ -39,16 +43,11 @@ do_test (void) return 1; } - /* Set an alarm for 1 second. The wrapper will expect this. */ - alarm (1); + delayed_exit (1); /* This call should never return. */ - pthread_spin_lock (&s); + xpthread_spin_lock (&s); puts ("2nd spin_lock returned"); return 1; } - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-stdio1.c b/nptl/tst-stdio1.c index 2d44c16..4250e53 100644 --- a/nptl/tst-stdio1.c +++ b/nptl/tst-stdio1.c @@ -21,6 +21,10 @@ #include #include +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" static void *tf (void *a) { @@ -43,14 +47,10 @@ do_test (void) _exit (1); } - pthread_join (th, NULL); + delayed_exit (1); + xpthread_join (th); puts ("join returned"); - return 0; + return 1; } - - -#define EXPECTED_SIGNAL SIGALRM -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/test-skeleton.c b/test-skeleton.c index 5a90c65..b24ce1d 100644 --- a/test-skeleton.c +++ b/test-skeleton.c @@ -559,3 +559,160 @@ main (int argc, char *argv[]) #endif } } + +/* The following functionality is only available if was + included before this file. */ +#ifdef _PTHREAD_H + +/* Call pthread_sigmask with error checking. */ +static void +xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset) +{ + if (pthread_sigmask (how, set, oldset) != 0) + { + write_message ("error: pthread_setmask failed\n"); + _exit (1); + } +} + +/* Call pthread_mutex_lock with error checking. */ +__attribute__ ((unused)) +static void +xpthread_mutex_lock (pthread_mutex_t *mutex) +{ + int ret = pthread_mutex_lock (mutex); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_mutex_lock: %m\n"); + exit (1); + } +} + +/* Call pthread_spin_lock with error checking. */ +__attribute__ ((unused)) +static void +xpthread_spin_lock (pthread_spinlock_t *lock) +{ + int ret = pthread_spin_lock (lock); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_spin_lock: %m\n"); + exit (1); + } +} + +/* Call pthread_cond_wait with error checking. */ +__attribute__ ((unused)) +static void +xpthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex) +{ + int ret = pthread_cond_wait (cond, mutex); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_cond_wait: %m\n"); + exit (1); + } +} + +/* Call pthread_barrier_wait with error checking. */ +__attribute__ ((unused)) +static int +xpthread_barrier_wait (pthread_barrier_t *barrier) +{ + int ret = pthread_barrier_wait (barrier); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) + { + errno = ret; + printf ("error: pthread_barrier_wait: %m\n"); + exit (1); + } + return ret; +} + +/* Call pthread_create with error checking. */ +static pthread_t +xpthread_create (pthread_attr_t *attr, + void *(*thread_func) (void *), void *closure) +{ + pthread_t thr; + int ret = pthread_create (&thr, attr, thread_func, closure); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_create: %m\n"); + exit (1); + } + return thr; +} + +/* Call pthread_detach with error checking. */ +static void +xpthread_detach (pthread_t thr) +{ + int ret = pthread_detach (thr); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_detach: %m\n"); + exit (1); + } +} + +/* Call pthread_join with error checking. */ +__attribute__ ((unused)) +static void * +xpthread_join (pthread_t thr) +{ + void *result; + int ret = pthread_join (thr, &result); + if (ret != 0) + { + errno = ret; + printf ("error: pthread_join: %m\n"); + exit (1); + } + return result; +} + +/* Used to implement the delayed_exit function defined below. */ +static void * +delayed_exit_thread (void *seconds_as_ptr) +{ + int seconds = (uintptr_t) seconds_as_ptr; + struct timespec delay = { seconds, 0 }; + struct timespec remaining = {}; + if (nanosleep (&delay, &remaining) != 0) + { + printf ("error: nanosleep: %m\n"); + _exit (1); + } + /* Exit the process sucessfully. */ + exit (0); + return NULL; +} + +/* Exit (with status 0) after SECONDS have elapsed, from a helper + thread. The process is terminated with the exit function, so + atexit handlers are executed. */ +__attribute__ ((unused)) +static void +delayed_exit (int seconds) +{ + /* Create the new thread with all signals blocked. */ + sigset_t all_blocked; + sigfillset (&all_blocked); + sigset_t old_set; + xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); + /* Create a detached thread. */ + pthread_t thr = xpthread_create + (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); + xpthread_detach (thr); + /* Restore the original signal mask. */ + xpthread_sigmask (SIG_SETMASK, &old_set, NULL); +} + +#endif /* _PTHREAD_H */