-
Notifications
You must be signed in to change notification settings - Fork 8
/
plasma_test.c
210 lines (179 loc) · 6.07 KB
/
plasma_test.c
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
* plasma_test - basic test framework support
*
* Copyright (c) 2013, Glue Logic LLC. All rights reserved. code()gluelogic.com
*
* This file is part of plasma.
*
* plasma 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.
*
* plasma 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 plasma. If not, see <http://www.gnu.org/licenses/>.
*/
/* _XOPEN_SOURCE 600 for pthread_barrier_t */
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600
#endif
#include "plasma_test.h"
#include "plasma_attr.h"
#include "plasma_feature.h"
#include "plasma_stdtypes.h"
#include <errno.h>
#include <stdio.h> /* fprintf() */
#include <stdlib.h> /* malloc() free() calloc() realloc() abort() */
#include <string.h> /* strerror() */
void
plasma_test_free (void *ptr)
{
free(ptr);
}
void *
plasma_test_malloc (size_t size)
{
return malloc(size);
}
void *
plasma_test_calloc (size_t nmemb, size_t size)
{
return calloc(nmemb, size);
}
void *
plasma_test_realloc (void *ptr, size_t size)
{
return realloc(ptr, size);
}
int
plasma_test_cond_failure (const char *func, const int line, const char *errstr)
{
fprintf(stderr, "%s:%d: test %s\n", func, line, errstr);
return false;
}
int
plasma_test_cond_idx_failure (const char *func, const int line,
const char *errstr, const int loopidx)
{
fprintf(stderr, "%s:%d: test %s ((idx=%d))\n", func, line, errstr, loopidx);
return false;
}
void
plasma_test_perror_abort (const char *func, const int line,
const char *errstr, int errnum)
{
if (errnum == 0)
errnum = errno;
fprintf(stderr, "%s:%d: %s: %s\n", func, line, errstr, strerror(errnum));
abort();
}
#ifdef PLASMA_FEATURE_POSIX
#include <pthread.h>
#include <unistd.h> /* _POSIX_BARRIERS (if supported) */
/* pthread barriers are optional POSIX extension not implemented on Mac OSX */
#if !defined(_POSIX_BARRIERS) || (_POSIX_BARRIERS-0) == -1
/* Brent Priddy provides a simple implementation of pthread barriers in
* http://stackoverflow.com/questions/3640853/performance-test-sem-t-v-s-dispatch-semaphore-t-and-pthread-once-t-v-s-dispat
* Note: code has been modified from original posted on link above */
typedef int pthread_barrierattr_t;
typedef struct
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int count;
int tripCount;
} pthread_barrier_t;
static int
pthread_barrier_init (pthread_barrier_t * const restrict barrier,
const pthread_barrierattr_t * const restrict attr
__attribute_unused__,
const unsigned int count)
{
if ( 0 != count
&& 0 == pthread_mutex_init(&barrier->mutex, 0)) {
if (0 == pthread_cond_init(&barrier->cond, 0)) {
barrier->tripCount = count;
barrier->count = 0;
return 0;
}
else
pthread_mutex_destroy(&barrier->mutex);
}
else if (count == 0)
errno = EINVAL;
return -1;
}
static int
pthread_barrier_destroy (pthread_barrier_t * const restrict barrier)
{
pthread_cond_destroy(&barrier->cond);
pthread_mutex_destroy(&barrier->mutex);
return 0;
}
static int
pthread_barrier_wait (pthread_barrier_t * const restrict barrier)
{
int rc=0; /*(rc 0 for waiters, non-zero for PTHREAD_BARRIER_SERIAL_THREAD)*/
pthread_mutex_lock(&barrier->mutex);
++barrier->count < barrier->tripCount
? pthread_cond_wait(&barrier->cond, &barrier->mutex)
: (pthread_cond_broadcast(&barrier->cond), (rc = 1));
pthread_mutex_unlock(&barrier->mutex);
return rc;
}
#endif /* !_POSIX_BARRIERS */
#elif defined(_WIN32)
/* XXX: see http://locklessinc.com/articles/pthreads_on_windows/ */
#endif /* defined(_WIN32) */
/* simple convenience framework to assist in running multithreaded tests
*
* thr_func() may (optionally) employ plasma_test_barrier_wait();
* thr_arg might be struct that includes shared storage array for thread status,
* as well as other data for thread, e.g. loop iterations for concurrent tests
*
* (Possible alternate implementation could have had caller provide array of
* initialized thr_arg that would be passed into each thread (thr_arg[n]) and
* stored back into that array upon pthread_join().)
*/
static pthread_barrier_t plasma_test_barrier;
void
plasma_test_nthreads (const int nthreads, void *(*thr_func)(void *),
void **thr_args, void **thr_rv)
{
pthread_t * const restrict thr_ids =
plasma_test_malloc(nthreads * sizeof(pthread_t));
void ** const thr_args_alloc = plasma_test_calloc(nthreads, sizeof(void*));
int n, rc;
if (thr_args == NULL)
thr_args = thr_args_alloc;
if (thr_rv == NULL)
thr_rv = thr_args_alloc;
if (thr_ids == NULL || thr_args == NULL || thr_rv == NULL)
PLASMA_TEST_PERROR_ABORT("plasma_test_malloc", errno);
if (0 != (rc = pthread_barrier_init(&plasma_test_barrier, NULL,
(unsigned int)nthreads)))
PLASMA_TEST_PERROR_ABORT("pthread_barrier_init", rc);
pthread_setconcurrency(nthreads);
for (n=0; n < nthreads; ++n) {
if (0 != (rc = pthread_create(&thr_ids[n],NULL,thr_func,thr_args[n])))
PLASMA_TEST_PERROR_ABORT("pthread_create", rc);
}
for (n=0; n < nthreads; ++n) {
if (0 != (rc = pthread_join(thr_ids[n], &thr_rv[n])))
PLASMA_TEST_PERROR_ABORT("pthread_join", rc);
}
pthread_setconcurrency(0);
pthread_barrier_destroy(&plasma_test_barrier);
plasma_test_free(thr_args_alloc);
plasma_test_free(thr_ids);
}
int
plasma_test_barrier_wait (void)
{
return pthread_barrier_wait(&plasma_test_barrier);
}