Files
hdf5/test/thread_id.c

163 lines
5.1 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the COPYING file, which can be found at the root of the source code *
* distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Check that a thread ID returned by H5TS_thread_id() possesses the
* following properties:
*
* 1 ID >= 1.
* 2 The ID is constant over the thread's lifetime.
* 3 No two threads share an ID during their lifetimes.
* 4 A thread's ID is available for reuse as soon as it is joined.
*/
#include <err.h>
/*
* Include required headers. This file tests internal library functions,
* so we include the private headers here.
*/
#include "testhdf5.h"
#if defined(H5_HAVE_THREADSAFE) && !defined(H5_HAVE_WIN_THREADS)
#define threads_failure(_call, _result) do { \
errx(EXIT_FAILURE, "%s.%d: " #_call ": %s", __func__, \
__LINE__, strerror(_result)); \
} while (false)
#define NTHREADS 5
static volatile bool failed = false;
static pthread_barrier_t barrier;
static bool used[NTHREADS];
static pthread_mutex_t used_lock;
static void
atomic_printf(const char *fmt, ...)
{
char buf[80];
va_list ap;
ssize_t nprinted, nwritten;
va_start(ap, fmt);
nprinted = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (nprinted == -1)
err(EXIT_FAILURE, "%s.%d: vsnprintf", __func__, __LINE__);
else if (nprinted >= (ssize_t)sizeof(buf))
errx(EXIT_FAILURE, "%s.%d: vsnprintf overflowed", __func__, __LINE__);
nwritten = write(STDOUT_FILENO, buf, (size_t)nprinted);
if (nwritten < nprinted) {
errx(EXIT_FAILURE, "%s.%d: write error or short write",
__func__, __LINE__);
}
}
/* Each thread runs this routine. The routine fetches the current
* thread's ID, makes sure that it is in the expected range, makes
* sure that in this round of testing, no two threads shared the
* same ID,
*/
static void *
thread_main(void H5_ATTR_UNUSED *arg)
{
uint64_t ntid, tid;
tid = H5TS_thread_id();
if (tid < 1 || NTHREADS < tid) {
atomic_printf("unexpected tid %" PRIu64 " FAIL\n", tid);
goto pre_barrier_error;
}
pthread_mutex_lock(&used_lock);
if (used[tid - 1]) {
atomic_printf("reused tid %" PRIu64 " FAIL\n", tid);
pthread_mutex_unlock(&used_lock);
goto pre_barrier_error;
}
used[tid - 1] = true;
pthread_mutex_unlock(&used_lock);
atomic_printf("tid %" PRIu64 " in [1, %d] PASS\n", tid, NTHREADS);
pthread_barrier_wait(&barrier);
ntid = H5TS_thread_id();
if (ntid != tid) {
atomic_printf("tid changed from %" PRIu64 " to %" PRIu64 " FAIL\n",
tid, ntid);
failed = true;
}
return NULL;
pre_barrier_error:
pthread_barrier_wait(&barrier);
failed = true;
return NULL;
}
int
main(void)
{
int i, rc, times;
pthread_t threads[NTHREADS];
/* Run H5open() to initialize the library's thread-ID freelist,
* mutex, etc.
*/
if (H5open() != SUCCEED)
errx(EXIT_FAILURE, "%s.%d: H5open failed", __func__, __LINE__);
if ((rc = pthread_mutex_init(&used_lock, NULL)) == -1)
threads_failure(pthread_mutex_init, rc);
if ((rc = pthread_barrier_init(&barrier, NULL, NTHREADS)) != 0)
threads_failure(pthread_barrier_init, rc);
/* Start the test threads and join them twice to make sure that
* the thread IDs are recycled in the second round.
*/
for (times = 0; times < 2; times++) {
for (i = 0; i < NTHREADS; i++)
used[i] = false; // access synchronized by thread create/join
for (i = 0; i < NTHREADS; i++) {
rc = pthread_create(&threads[i], NULL, thread_main, NULL);
if (rc != 0)
threads_failure(pthread_create, rc);
}
for (i = 0; i < NTHREADS; i++) {
rc = pthread_join(threads[i], NULL);
if (rc != 0)
threads_failure(pthread_join, rc);
}
for (i = 0; i < NTHREADS; i++) {
if (!used[i]) // access synchronized by thread create/join
errx(EXIT_FAILURE, "thread ID %d did not run.", i + 1);
}
}
if ((rc = pthread_barrier_destroy(&barrier)) != 0)
threads_failure(pthread_barrier_destroy, rc);
return failed ? EXIT_FAILURE : EXIT_SUCCESS;
}
#else /*H5_HAVE_THREADSAFE && !H5_HAVE_WIN_THREADS*/
int
main(void)
{
HDfprintf(stderr, "not implemented in this configuration.\n");
return EXIT_SUCCESS;
}
#endif /*H5_HAVE_THREADSAFE && !H5_HAVE_WIN_THREADS*/