Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/ck/include/ck_bytelock.h
48255 views
1
/*
2
* Copyright 2010-2015 Samy Al Bahra.
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#ifndef CK_BYTELOCK_H
28
#define CK_BYTELOCK_H
29
30
/*
31
* The implementations here are derived from the work described in:
32
* Dice, D. and Shavit, N. 2010. TLRW: return of the read-write lock.
33
* In Proceedings of the 22nd ACM Symposium on Parallelism in Algorithms
34
* and Architectures (Thira, Santorini, Greece, June 13 - 15, 2010).
35
* SPAA '10. ACM, New York, NY, 284-293.
36
*/
37
38
#include <ck_cc.h>
39
#include <ck_md.h>
40
#include <ck_pr.h>
41
#include <ck_stdbool.h>
42
#include <ck_stddef.h>
43
#include <ck_limits.h>
44
45
struct ck_bytelock {
46
unsigned int owner;
47
unsigned int n_readers;
48
uint8_t readers[CK_MD_CACHELINE - sizeof(unsigned int) * 2] CK_CC_ALIGN(8);
49
};
50
typedef struct ck_bytelock ck_bytelock_t;
51
52
#define CK_BYTELOCK_INITIALIZER { 0, 0, {0} }
53
#define CK_BYTELOCK_UNSLOTTED UINT_MAX
54
55
CK_CC_INLINE static void
56
ck_bytelock_init(struct ck_bytelock *bytelock)
57
{
58
unsigned int i;
59
60
bytelock->owner = 0;
61
bytelock->n_readers = 0;
62
for (i = 0; i < sizeof bytelock->readers; i++)
63
bytelock->readers[i] = false;
64
65
ck_pr_barrier();
66
return;
67
}
68
69
#ifdef CK_F_PR_LOAD_64
70
#define CK_BYTELOCK_LENGTH sizeof(uint64_t)
71
#define CK_BYTELOCK_LOAD ck_pr_load_64
72
#define CK_BYTELOCK_TYPE uint64_t
73
#elif defined(CK_F_PR_LOAD_32)
74
#define CK_BYTELOCK_LENGTH sizeof(uint32_t)
75
#define CK_BYTELOCK_LOAD ck_pr_load_32
76
#define CK_BYTELOCK_TYPE uint32_t
77
#else
78
#error Unsupported platform.
79
#endif
80
81
CK_CC_INLINE static void
82
ck_bytelock_write_lock(struct ck_bytelock *bytelock, unsigned int slot)
83
{
84
CK_BYTELOCK_TYPE *readers = (void *)bytelock->readers;
85
unsigned int i;
86
87
/* Announce upcoming writer acquisition. */
88
while (ck_pr_cas_uint(&bytelock->owner, 0, slot) == false)
89
ck_pr_stall();
90
91
/* If we are slotted, we might be upgrading from a read lock. */
92
if (slot <= sizeof bytelock->readers)
93
ck_pr_store_8(&bytelock->readers[slot - 1], false);
94
95
/*
96
* Wait for slotted readers to drain out. This also provides the
97
* lock acquire semantics.
98
*/
99
ck_pr_fence_atomic_load();
100
101
for (i = 0; i < sizeof(bytelock->readers) / CK_BYTELOCK_LENGTH; i++) {
102
while (CK_BYTELOCK_LOAD(&readers[i]) != false)
103
ck_pr_stall();
104
}
105
106
/* Wait for unslotted readers to drain out. */
107
while (ck_pr_load_uint(&bytelock->n_readers) != 0)
108
ck_pr_stall();
109
110
ck_pr_fence_lock();
111
return;
112
}
113
114
#undef CK_BYTELOCK_LENGTH
115
#undef CK_BYTELOCK_LOAD
116
#undef CK_BYTELOCK_TYPE
117
118
CK_CC_INLINE static void
119
ck_bytelock_write_unlock(struct ck_bytelock *bytelock)
120
{
121
122
ck_pr_fence_unlock();
123
ck_pr_store_uint(&bytelock->owner, 0);
124
return;
125
}
126
127
CK_CC_INLINE static void
128
ck_bytelock_read_lock(struct ck_bytelock *bytelock, unsigned int slot)
129
{
130
131
if (ck_pr_load_uint(&bytelock->owner) == slot) {
132
ck_pr_store_8(&bytelock->readers[slot - 1], true);
133
ck_pr_fence_strict_store();
134
ck_pr_store_uint(&bytelock->owner, 0);
135
return;
136
}
137
138
/* Unslotted threads will have to use the readers counter. */
139
if (slot > sizeof bytelock->readers) {
140
for (;;) {
141
ck_pr_inc_uint(&bytelock->n_readers);
142
ck_pr_fence_atomic_load();
143
if (ck_pr_load_uint(&bytelock->owner) == 0)
144
break;
145
ck_pr_dec_uint(&bytelock->n_readers);
146
147
while (ck_pr_load_uint(&bytelock->owner) != 0)
148
ck_pr_stall();
149
}
150
151
ck_pr_fence_lock();
152
return;
153
}
154
155
slot -= 1;
156
for (;;) {
157
#ifdef CK_F_PR_FAA_8
158
ck_pr_fas_8(&bytelock->readers[slot], true);
159
ck_pr_fence_atomic_load();
160
#else
161
ck_pr_store_8(&bytelock->readers[slot], true);
162
ck_pr_fence_store_load();
163
#endif
164
165
/*
166
* If there is no owner at this point, our slot has
167
* already been published and it is guaranteed no
168
* write acquisition will succeed until we drain out.
169
*/
170
if (ck_pr_load_uint(&bytelock->owner) == 0)
171
break;
172
173
ck_pr_store_8(&bytelock->readers[slot], false);
174
while (ck_pr_load_uint(&bytelock->owner) != 0)
175
ck_pr_stall();
176
}
177
178
ck_pr_fence_lock();
179
return;
180
}
181
182
CK_CC_INLINE static void
183
ck_bytelock_read_unlock(struct ck_bytelock *bytelock, unsigned int slot)
184
{
185
186
ck_pr_fence_unlock();
187
188
if (slot > sizeof bytelock->readers)
189
ck_pr_dec_uint(&bytelock->n_readers);
190
else
191
ck_pr_store_8(&bytelock->readers[slot - 1], false);
192
193
return;
194
}
195
196
#endif /* CK_BYTELOCK_H */
197
198