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
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
void
barrierwait(pthread_barrier_t *barrier)
{
#ifndef SINGLE_THREADED
int r = pthread_barrier_wait(barrier);
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) {
errno = r;
eprintf("pthread_barrier_wait:");
}
#else
(void) barrier;
#endif
}
void
barriersend(struct barrier_group *group, struct global_data *global, void (*action)(struct algorithm *, struct global_data *))
{
size_t index;
global->action = action;
if (group->nthreads)
barrierwait(&group->barrier);
for (index = 0; index < global->nalgorithms; index += group->nthreads + 1U)
(*action)(&global->algorithms[index], global);
if (group->nthreads)
barrierwait(&group->barrier);
}
#ifndef SINGLE_THREADED
static void *
slaveloop(void *thread_param)
{
struct thread_data *data = thread_param;
void (*action)(struct algorithm *, struct global_data *);
size_t index;
for (;;) {
barrierwait(&data->group->barrier);
action = data->global->action;
if (!action)
break;
for (index = data->index; index < data->global->nalgorithms; index += data->group->nthreads + 1U)
(*action)(&data->global->algorithms[index], data->global);
barrierwait(&data->group->barrier);
}
return NULL;
}
#endif
void
createbarriergroup(struct barrier_group *group_out, size_t count, struct global_data *global)
{
#ifndef SINGLE_THREADED
size_t i;
group_out->nthreads = count - 1U;
group_out->threads = NULL;
if (!group_out->nthreads)
return;
group_out->threads = ecalloc(group_out->nthreads, sizeof(*group_out->threads));
if ((errno = pthread_barrier_init(&group_out->barrier, NULL, (unsigned)count)))
eprintf("pthread_barrier_init NULL %u:", (unsigned)count);
for (i = 0; i < group_out->nthreads; i++) {
group_out->threads[i].group = group_out;
group_out->threads[i].global = global;
group_out->threads[i].index = i + 1U;
errno = pthread_create(&group_out->threads[i].thread, NULL, &slaveloop, &group_out->threads[i]);
if (errno)
eprintf("pthread_create NULL:");
}
#else
group_out->nthreads = 0U;
group_out->threads = NULL;
(void) global;
(void) count;
#endif
}
void
killbarriergroup(struct barrier_group *group, struct global_data *global)
{
#ifndef SINGLE_THREADED
size_t i;
if (!group->nthreads)
return;
global->action = NULL;
for (i = 0; i < group->nthreads; i++)
group->threads[i].global = global;
barrierwait(&group->barrier);
for (i = 0; i < group->nthreads; i++)
if ((errno = pthread_join(group->threads[i].thread, NULL)))
weprintf("pthread_join:");
pthread_barrier_destroy(&group->barrier);
free(group->threads);
#else
(void) group;
(void) global;
#endif
}
|