-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsymm_barrier.h
113 lines (96 loc) · 2.83 KB
/
symm_barrier.h
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
/* SPDX-License-Identifier: MIT */
/**
* @file symm_barrier.h
* @brief The symmetric barrier
* which built with the 'asym-barrier' library.
*
* It was implemented by the mixing of the
* 'asym-barrier' library and the 'ticket-lock' approach.
*
* This is not efficient compared to existing methods such as the 'pthread_barrier',
* but maybe an example case showing how to use the 'asym-barrier'.
*
* It treats the updater and waiter equally by internally calls the check function
* instead of the CPU spinning of the 'ticket-lock' algorithm.
*
* @author Hyeonho Seo a.k.a Revimal ([email protected])
*/
#ifndef SYMM_BARRIER_H
#define SYMM_BARRIER_H
#include "asym_barrier.h"
struct symm_barrier_obj
{
uint64_t workers;
uint64_t waiting;
uint64_t serving;
asym_barrier_t asymb;
} ASYM_BARRIER_CACHE_ALIGNED;
typedef struct symm_barrier_obj ASYM_BARRIER_CACHE_ALIGNED symm_barrier_t;
/**
* @brief Initialize a symmetric barrier object.
*
* @param symmb
* The pointer to a symmetric barrier object.
* @param workters
* The number of total threads.
*/
static inline void symm_barrier_init(symm_barrier_t *symmb, uint64_t workers)
{
if (ASYM_BARRIER_COMP_UNLIKELY(!symmb))
return;
atomic_store_explicit(&symmb->workers, workers, memory_order_relaxed);
atomic_store_explicit(&symmb->waiting, 0, memory_order_relaxed);
atomic_store_explicit(&symmb->serving, 0, memory_order_relaxed);
if (ASYM_BARRIER_COMP_UNLIKELY(symmb->workers > 1))
asym_barrier_init(&symmb->asymb, (symmb->workers - 1));
return;
}
/**
* @brief Update the period of a symmetric barrier object.
*
* @param symmb
* The pointer to a symmetric barrier object.
*
* @param synced
* If 0, the caller thread does not wait for others.
*/
static inline void symm_barrier_update(symm_barrier_t *symmb, unsigned synced)
{
if (ASYM_BARRIER_COMP_LIKELY(!!symmb && symmb->workers > 1))
{
register uint64_t expect = atomic_fetch_add_explicit(
&symmb->waiting, 1, memory_order_acquire);
while (expect != atomic_load_explicit(&symmb->serving, memory_order_relaxed))
asym_barrier_check(&symmb->asymb);
asym_barrier_update(&symmb->asymb, synced);
}
return;
}
/**
* @brief Commit the period of a symmetric barrier object.
*
* @param symmb
* The pointer to a symmetric barrier object.
*/
static inline void symm_barrier_commit(symm_barrier_t *symmb)
{
if (ASYM_BARRIER_COMP_LIKELY(!!symmb && symmb->workers > 1))
{
asym_barrier_commit(&symmb->asymb);
(void)atomic_fetch_add_explicit(&symmb->serving, 1, memory_order_release);
}
return;
}
/**
* @brief Check the period of a symmetric barrier object.
*
* @param symmb
* The pointer to a symmetric barrier object.
*/
static inline void symm_barrier_check(symm_barrier_t *symmb)
{
if (ASYM_BARRIER_COMP_LIKELY(!!symmb && symmb->workers > 1))
asym_barrier_check(&symmb->asymb);
return;
}
#endif /* SYMM_BARRIER_H */