File: mtest_thread.c

package info (click to toggle)
mpich 4.3.0%2Breally4.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, trixie
  • size: 419,120 kB
  • sloc: ansic: 1,215,557; cpp: 74,755; javascript: 40,763; f90: 20,649; sh: 18,463; xml: 14,418; python: 14,397; perl: 13,772; makefile: 9,279; fortran: 8,063; java: 4,553; asm: 324; ruby: 176; lisp: 19; php: 8; sed: 4
file content (155 lines) | stat: -rw-r--r-- 4,111 bytes parent folder | download | duplicates (2)
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 */