1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
/*
* Copyright (C) by Argonne National Laboratory
* See COPYRIGHT in top-level directory
*/
#include <stdio.h>
#include <stdlib.h>
#include "mpitest.h"
/* This file provides a portability layer for using threads. */
#if THREAD_PACKAGE_NAME == THREAD_PACKAGE_NONE
/* Only empty initialization and finalization functions are supported. */
void MTest_init_thread_pkg(void)
{
}
void MTest_finalize_thread_pkg(void)
{
}
#else /* THREAD_PACKAGE_NAME != THREAD_PACKAGE_NONE */
/*
Define macro to override gcc strict flags,
-D_POSIX_C_SOURCE=199506L, -std=c89 and -std=c99,
that disallow pthread_barrier_t and friends.
*/
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200112L
#endif
/* We remember all of the threads we create; this similifies terminating
(joining) them. */
#ifndef MTEST_MAX_THREADS
#define MTEST_MAX_THREADS 16
#endif
static MTEST_THREAD_HANDLE threads[MTEST_MAX_THREADS];
/* access w/o a lock is broken, but "volatile" should help reduce the amount of
* speculative loading/storing */
static volatile int nthreads = 0;
/* to-be-defined in the thread package, or default routines will be used */
#undef HAVE_MTEST_THREAD_BARRIER
#undef HAVE_MTEST_INIT_THREAD_PKG
#if !defined(THREAD_PACKAGE_NAME)
#error "thread package (THREAD_PACKAGE_NAME) not defined"
#elif THREAD_PACKAGE_NAME == THREAD_PACKAGE_WIN
#include "mtest_thread_win.h"
#elif THREAD_PACKAGE_NAME == THREAD_PACKAGE_POSIX || THREAD_PACKAGE_NAME == THREAD_PACKAGE_SOLARIS
#include "mtest_thread_pthread.h"
#elif THREAD_PACKAGE_NAME == THREAD_PACKAGE_ARGOBOTS
#include "mtest_thread_abt.h"
#else
#error "thread package (THREAD_PACKAGE_NAME) unknown"
#endif
/* Default routines */
#if !defined(HAVE_MTEST_THREAD_BARRIER)
static MTEST_THREAD_LOCK_TYPE barrierLock;
static volatile int phase = 0;
static volatile int c[2] = { -1, -1 };
int MTest_thread_barrier_init(void)
{
return MTest_thread_lock_create(&barrierLock);
}
int MTest_thread_barrier_free(void)
{
return MTest_thread_lock_free(&barrierLock);
}
#define LOCK_ERR_CHECK(err_) \
if (err_) { \
fprintf(stderr, "Lock failed in barrier!\n"); \
return err_; \
}
/* This is a generic barrier implementation. To ensure that tests don't
silently fail, this both prints an error message and returns an error
result on any failure. */
int MTest_thread_barrier(int nt)
{
volatile int *cntP;
int err = 0;
int num_left;
if (nt < 0)
nt = nthreads;
/* Force a write barrier by using lock/unlock */
err = MTest_thread_lock(&barrierLock);
LOCK_ERR_CHECK(err);
cntP = &c[phase];
/* printf("[%d] cnt = %d, phase = %d\n", pthread_self(), *cntP, phase); */
/* The first thread to enter will reset the counter */
if (*cntP < 0)
*cntP = nt;
/* printf("phase = %d, cnt = %d\n", phase, *cntP); */
/* The last thread to enter will force the counter to be negative */
if (*cntP == 1) {
/* printf("[%d] changing phase from %d\n", pthread_self(), phase); */
phase = !phase;
c[phase] = -1;
*cntP = 0;
}
/* Really need a write barrier here */
*cntP = *cntP - 1;
num_left = *cntP;
err = MTest_thread_unlock(&barrierLock);
LOCK_ERR_CHECK(err);
/* wait for other threads */
while (num_left > 0) {
err = MTest_thread_lock(&barrierLock);
LOCK_ERR_CHECK(err);
/* TODO: This would be improved with atomic ops instead of using
* a mutex. Integrating MPL for portable atomics would be an
* improvement. */
num_left = *cntP;
err = MTest_thread_unlock(&barrierLock);
LOCK_ERR_CHECK(err);
}
return err;
}
#endif /* Default barrier routine */
#if !defined(HAVE_MTEST_INIT_THREAD_PKG)
void MTest_init_thread_pkg(void)
{
}
void MTest_finalize_thread_pkg(void)
{
}
#endif /* THREAD_PACKAGE_NAME != THREAD_PACKAGE_NONE */
#endif /* Default MTest_init_thread_pkg */
|