summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--test/thread_id.c140
1 files changed, 139 insertions, 1 deletions
diff --git a/test/thread_id.c b/test/thread_id.c
index af36625..818ab4a 100644
--- a/test/thread_id.c
+++ b/test/thread_id.c
@@ -42,6 +42,136 @@ my_errx(int code, const char *fmt, ...)
#if defined(H5_HAVE_THREADSAFE) && !defined(H5_HAVE_WIN_THREADS)
+#if defined(H5_HAVE_DARWIN)
+
+typedef struct _pthread_barrierattr {
+ uint8_t unused;
+} pthread_barrierattr_t;
+
+typedef struct _pthread_barrier {
+ uint32_t magic;
+ unsigned int count;
+ uint64_t nentered;
+ pthread_cond_t cv;
+ pthread_mutex_t mtx;
+} pthread_barrier_t;
+
+int pthread_barrier_init(pthread_barrier_t *, const pthread_barrierattr_t *,
+ unsigned int);
+int pthread_barrier_wait(pthread_barrier_t *);
+int pthread_barrier_destroy(pthread_barrier_t *);
+
+static const uint32_t barrier_magic = 0xf00dd00f;
+
+int
+pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, unsigned int count)
+{
+ int rc;
+
+ if (count == 0)
+ return EINVAL;
+
+ if (attr != NULL)
+ return EINVAL;
+
+ memset(barrier, 0, sizeof(*barrier));
+
+ barrier->count = count;
+
+ if ((rc = pthread_cond_init(&barrier->cv, NULL)) != 0)
+ return rc;
+
+ if ((rc = pthread_mutex_init(&barrier->mtx, NULL)) != 0) {
+ (void)pthread_cond_destroy(&barrier->cv);
+ return rc;
+ }
+
+ barrier->magic = barrier_magic;
+
+ return 0;
+}
+
+static void
+barrier_lock(pthread_barrier_t *barrier)
+{
+ int rc;
+
+ if ((rc = pthread_mutex_lock(&barrier->mtx)) != 0) {
+ my_errx(EXIT_FAILURE, "%s: pthread_mutex_lock: %s", __func__,
+ strerror(rc));
+ }
+}
+
+static void
+barrier_unlock(pthread_barrier_t *barrier)
+{
+ int rc;
+
+ if ((rc = pthread_mutex_unlock(&barrier->mtx)) != 0) {
+ my_errx(EXIT_FAILURE, "%s: pthread_mutex_unlock: %s", __func__,
+ strerror(rc));
+ }
+}
+
+int
+pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ int rc;
+
+ barrier_lock(barrier);
+ if (barrier->magic != barrier_magic)
+ rc = EINVAL;
+ else if (barrier->nentered % barrier->count != 0)
+ rc = EBUSY;
+ else {
+ rc = 0;
+ barrier->magic = ~barrier->magic;
+ }
+ barrier_unlock(barrier);
+
+ if (rc != 0)
+ return rc;
+
+ (void)pthread_cond_destroy(&barrier->cv);
+ (void)pthread_mutex_destroy(&barrier->mtx);
+
+ return 0;
+}
+
+int
+pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ int rc;
+ uint64_t threshold;
+
+ if (barrier == NULL)
+ return EINVAL;
+
+ barrier_lock(barrier);
+ if (barrier->magic != barrier_magic) {
+ rc = EINVAL;
+ goto out;
+ }
+ /* Compute the release `threshold`. All threads entering with count = 5
+ * and `nentered` in [0, 4] should be released once `nentered` reaches 5:
+ * call 5 the release `threshold`. All threads entering with count = 5
+ * and `nentered` in [5, 9] should be released once `nentered` reaches 10.
+ */
+ threshold = (barrier->nentered / barrier->count + 1) * barrier->count;
+ barrier->nentered++;
+ while (barrier->nentered < threshold) {
+ if ((rc = pthread_cond_wait(&barrier->cv, &barrier->mtx)) != 0)
+ goto out;
+ }
+ rc = pthread_cond_broadcast(&barrier->cv);
+out:
+ barrier_unlock(barrier);
+ return rc;
+}
+
+#endif /* H5_HAVE_DARWIN */
+
static void my_err(int, const char *, ...) H5_ATTR_FORMAT(printf, 2, 3);
static void
@@ -96,7 +226,15 @@ atomic_printf(const char *fmt, ...)
/* 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,
+ * same ID, and checks that each thread's ID is constant over its lifetime.
+ *
+ * main() checks that every ID in [1, NTHREADS] is used in each round
+ * of testing. All NTHREADS threads synchronize on a barrier after each
+ * has fetched its ID. The barrier guarantees that all threads' lifetimes
+ * overlap at least momentarily, so the IDs will be unique, and there
+ * will be NTHREADS of them. Further, since thread IDs are assigned
+ * starting with 1, and the number of threads with IDs alive never exceeds
+ * NTHREADS, the least ID has to be 1 and the greatest, NTHREADS.
*/
static void *
thread_main(void H5_ATTR_UNUSED *arg)