diff options
Diffstat (limited to 'nptl')
-rw-r--r-- | nptl/Makefile | 2 | ||||
-rw-r--r-- | nptl/tst-pthread-timedlock-lockloop.c | 138 |
2 files changed, 139 insertions, 1 deletions
diff --git a/nptl/Makefile b/nptl/Makefile index 94d805f..ddd83df 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -298,7 +298,7 @@ tests = tst-attr2 tst-attr3 tst-default-attr \ tst-thread-affinity-sched \ tst-pthread-defaultattr-free \ tst-pthread-attr-sigmask \ - + tst-pthread-timedlock-lockloop tests-container = tst-pthread-getattr diff --git a/nptl/tst-pthread-timedlock-lockloop.c b/nptl/tst-pthread-timedlock-lockloop.c new file mode 100644 index 0000000..bd5ed77 --- /dev/null +++ b/nptl/tst-pthread-timedlock-lockloop.c @@ -0,0 +1,138 @@ +/* Make sure pthread_mutex_timedlock doesn't return spurious error codes. + + Copyright (C) 2020 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 + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <support/check.h> +#include <support/timespec.h> +#include <support/xsignal.h> +#include <support/xthread.h> +#include <support/xtime.h> +#include <time.h> +#include <unistd.h> + +#define NANO_PER_SEC 1000000000LL +#define TIMEOUT (NANO_PER_SEC / 1000LL) +#define NUM_THREADS 50 +#define RETEST_TIMES 100 + +static pthread_mutex_t mutex; +static int runs; +static clockid_t clockid; + +static void +signal_handler (int sig_num) +{ + TEST_COMPARE (sig_num, SIGUSR1); +} + +/* Call pthread_mutex_timedlock()/pthread_mutex_unlock() repetitively, hoping + that one of them returns EAGAIN or EINTR unexpectedly. */ +static void * +worker_timedlock (void *arg) +{ + for (unsigned int run = 0; run < runs; run++) + { + struct timespec abs_time = timespec_add (xclock_now (CLOCK_REALTIME), + make_timespec (0, 1000000)); + + int ret = pthread_mutex_timedlock (&mutex, &abs_time); + + if (ret == 0) + xpthread_mutex_unlock (&mutex); + + TEST_VERIFY_EXIT (ret == 0 || ret == ETIMEDOUT); + } + return NULL; +} + +static void * +worker_clocklock (void *arg) +{ + for (unsigned int run = 0; run < runs; run++) + { + struct timespec time = + timespec_add (xclock_now (clockid), make_timespec (0, 1000000)); + + int ret = pthread_mutex_clocklock (&mutex, clockid, &time); + + if (ret == 0) + xpthread_mutex_unlock (&mutex); + + TEST_VERIFY_EXIT (ret == 0 || ret == ETIMEDOUT); + } + return NULL; +} + +static int +run_test_set (void *(*worker) (void *)) +{ + pthread_t workers[NUM_THREADS]; + + /* Check if default pthread_mutex_{timed,clock}lock with valid arguments + returns either 0 or ETIMEDOUT. Since there is no easy way to force + the error condition, the test creates multiple threads which in turn + issues pthread_mutex_timedlock multiple times. */ + runs = 100; + for (int run = 0; run < RETEST_TIMES; run++) + { + for (int i = 0; i < NUM_THREADS; i++) + workers[i] = xpthread_create (NULL, worker, NULL); + for (int i = 0; i < NUM_THREADS; i++) + xpthread_join (workers[i]); + } + + /* The idea is similar to previous tests, but we check if + pthread_mutex_{timed,clock}lock does not return EINTR. */ + pthread_t thread; + runs = 1; + for (int i = 0; i < RETEST_TIMES * 1000; i++) + { + xpthread_mutex_lock (&mutex); + thread = xpthread_create (NULL, worker, NULL); + /* Sleep just a little bit to reach the lock on the worker thread. */ + usleep (10); + pthread_kill (thread, SIGUSR1); + xpthread_mutex_unlock (&mutex); + xpthread_join (thread); + } + + return 0; +} + +static int +do_test (void) +{ + + xsignal (SIGUSR1, signal_handler); + + xpthread_mutex_init (&mutex, NULL); + + run_test_set (worker_timedlock); + clockid = CLOCK_REALTIME; + run_test_set (worker_clocklock); + clockid = CLOCK_MONOTONIC; + run_test_set (worker_clocklock); + return 0; +} + +#include <support/test-driver.c> |