nptl: Avoid expected SIGALRM in most tests [BZ #20432]

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.
This commit is contained in:
Florian Weimer 2016-08-26 19:27:16 +02:00
parent 0ac8ee53e8
commit 7e625f7e85
15 changed files with 293 additions and 101 deletions

View File

@ -1,3 +1,45 @@
2016-08-26 Florian Weimer <fweimer@redhat.com>
[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.
2016-08-26 H.J. Lu <hongjiu.lu@intel.com> 2016-08-26 H.J. Lu <hongjiu.lu@intel.com>
* sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't

View File

@ -22,6 +22,10 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
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 /* Note that this test requires more than the standard. It is
required that there are no spurious wakeups if only more readers required that there are no spurious wakeups if only more readers
@ -50,7 +54,8 @@ tf (void *arg)
} }
/* This call should never return. */ /* 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. */ /* We should never get here. */
exit (1); exit (1);
@ -96,17 +101,11 @@ do_test (void)
} }
} }
/* Set an alarm for 1 second. The wrapper will expect this. */ delayed_exit (1);
alarm (1);
/* This call should never return. */ /* This call should never return. */
pthread_cond_wait (&cond, &mut); xpthread_cond_wait (&cond, &mut);
puts ("cond_wait returned"); puts ("error: pthread_cond_wait in do_test returned");
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -23,6 +23,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include "eintr.c" #include "eintr.c"
@ -92,13 +97,8 @@ do_test (void)
} }
} }
delayed_exit (3);
/* This call must never return. */
(void) tf1 (NULL); (void) tf1 (NULL);
/* NOTREACHED */ return 1;
return 0;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TIMEOUT 3
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -24,6 +24,11 @@
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include "eintr.c" #include "eintr.c"
@ -103,6 +108,7 @@ do_test (void)
exit (1); exit (1);
} }
delayed_exit (3);
/* This call must never return. */ /* This call must never return. */
e = pthread_mutex_lock (&m1); e = pthread_mutex_lock (&m1);
printf ("main: mutex_lock returned: %s\n", printf ("main: mutex_lock returned: %s\n",
@ -110,8 +116,3 @@ do_test (void)
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TIMEOUT 3
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -23,6 +23,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include "eintr.c" #include "eintr.c"
@ -56,16 +61,9 @@ do_test (void)
exit (1); exit (1);
} }
delayed_exit (1);
/* This call must never return. */ /* This call must never return. */
e = pthread_join (th, NULL); xpthread_join (th);
puts ("error: pthread_join returned");
if (e == EINTR) return 1;
puts ("pthread_join returned with EINTR");
return 0;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TIMEOUT 1
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -23,6 +23,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include "eintr.c" #include "eintr.c"
@ -40,16 +45,9 @@ do_test (void)
exit (1); exit (1);
} }
delayed_exit (1);
/* This call must never return. */ /* This call must never return. */
int e = pthread_barrier_wait (&b); xpthread_barrier_wait (&b);
puts ("error: pthread_barrier_wait returned");
if (e == EINTR) return 1;
puts ("pthread_join returned with EINTR");
return 0;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TIMEOUT 1
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -24,6 +24,11 @@
#include <string.h> #include <string.h>
#include <sys/time.h> #include <sys/time.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include "eintr.c" #include "eintr.c"
@ -66,15 +71,9 @@ do_test (void)
exit (1); exit (1);
} }
delayed_exit (3);
/* This call must never return. */ /* This call must never return. */
e = pthread_cond_wait (&c, &m); xpthread_cond_wait (&c, &m);
printf ("main: cond_wait returned: %s\n", puts ("error: pthread_cond_wait returned");
strerror_r (e, buf, sizeof (buf))); return 1;
return 0;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TIMEOUT 3
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -4,6 +4,10 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static void * static void *
tf (void *arg) tf (void *arg)
@ -28,13 +32,11 @@ do_test (void)
return 1; return 1;
} }
delayed_exit (1);
/* Terminate only this thread. */ /* Terminate only this thread. */
pthread_exit (NULL); pthread_exit (NULL);
/* NOTREACHED */ /* NOTREACHED */
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -5,6 +5,10 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static pthread_barrier_t b; static pthread_barrier_t b;
@ -69,13 +73,11 @@ do_test (void)
exit (1); exit (1);
} }
delayed_exit (3);
/* Terminate only this thread. */ /* Terminate only this thread. */
pthread_exit (NULL); pthread_exit (NULL);
/* NOTREACHED */ /* NOTREACHED */
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -23,6 +23,11 @@
#include <errno.h> #include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#ifndef TEST_FUNCTION
static int do_test (void);
# define TEST_FUNCTION do_test ()
#endif
#include "../test-skeleton.c"
#ifndef ATTR #ifndef ATTR
pthread_mutexattr_t *attr; pthread_mutexattr_t *attr;
@ -62,18 +67,10 @@ do_test (void)
return 1; return 1;
} }
/* Set an alarm for 1 second. The wrapper will expect this. */ delayed_exit (1);
alarm (1);
/* This call should never return. */ /* This call should never return. */
pthread_mutex_lock (&m); xpthread_mutex_lock (&m);
puts ("2nd mutex_lock returned"); puts ("2nd mutex_lock returned");
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#ifndef TEST_FUNCTION
# define TEST_FUNCTION do_test ()
#endif
#include "../test-skeleton.c"

View File

@ -22,6 +22,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
static pthread_rwlock_t r; static pthread_rwlock_t r;
@ -65,22 +69,16 @@ do_test (void)
return 1; return 1;
} }
/* Set an alarm for 1 second. The wrapper will expect this. */
alarm (1);
if (pthread_create (&th, NULL, tf, NULL) != 0) if (pthread_create (&th, NULL, tf, NULL) != 0)
{ {
puts ("create failed"); puts ("create failed");
return 1; return 1;
} }
delayed_exit (1);
/* This call should never return. */ /* This call should never return. */
pthread_mutex_lock (&m); xpthread_mutex_lock (&m);
puts ("2nd mutex_lock returned"); puts ("2nd mutex_lock returned");
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -17,11 +17,16 @@
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include <errno.h> #include <errno.h>
#include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static int static int
do_test (void) do_test (void)
@ -34,8 +39,7 @@ do_test (void)
return 1; return 1;
} }
/* Set an alarm for 1 second. The wrapper will expect this. */ delayed_exit (1);
alarm (1);
if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
{ {
@ -47,7 +51,3 @@ do_test (void)
puts ("wait succeeded"); puts ("wait succeeded");
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -21,6 +21,10 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static int static int
do_test (void) do_test (void)
@ -39,16 +43,11 @@ do_test (void)
return 1; return 1;
} }
/* Set an alarm for 1 second. The wrapper will expect this. */ delayed_exit (1);
alarm (1);
/* This call should never return. */ /* This call should never return. */
pthread_spin_lock (&s); xpthread_spin_lock (&s);
puts ("2nd spin_lock returned"); puts ("2nd spin_lock returned");
return 1; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -21,6 +21,10 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static void *tf (void *a) static void *tf (void *a)
{ {
@ -43,14 +47,10 @@ do_test (void)
_exit (1); _exit (1);
} }
pthread_join (th, NULL); delayed_exit (1);
xpthread_join (th);
puts ("join returned"); puts ("join returned");
return 0; return 1;
} }
#define EXPECTED_SIGNAL SIGALRM
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -559,3 +559,160 @@ main (int argc, char *argv[])
#endif #endif
} }
} }
/* The following functionality is only available if <pthread.h> 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 */