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
|
#include "lightrwlock.h"
#include <util/system/spinlock.h>
#if defined(_linux_)
using namespace NS_LightRWLock;
void TLightRWLock::WaitForUntrappedShared() {
for (;;) {
for (ui32 i = 0; i < SpinCount_; ++i) {
SpinLockPause();
if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0)
return;
}
SequenceStore(UnshareFutex_, 1);
if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) {
AtomicStore(UnshareFutex_, 0);
return;
}
FutexWait(UnshareFutex_, 1);
}
}
void TLightRWLock::WaitForExclusiveAndUntrappedShared() {
for (;;) {
for (ui32 i = 0; i < SpinCount_; ++i) {
SpinLockPause();
if (AtomicLoad(Counter_) >= 0)
goto try_to_get_lock;
if (AtomicLoad(TrappedFutex_) == 1)
goto skip_store_trapped;
}
SequenceStore(TrappedFutex_, 1);
skip_store_trapped:
if (AtomicLoad(Counter_) < 0) {
FutexWait(TrappedFutex_, 1);
}
try_to_get_lock:
if (!AtomicSetBit(Counter_, 31))
break;
}
for (;;) {
for (ui32 i = 0; i < SpinCount_; ++i) {
if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0)
return;
SpinLockPause();
}
SequenceStore(UnshareFutex_, 1);
if ((AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) {
AtomicStore(UnshareFutex_, 0);
return;
}
FutexWait(UnshareFutex_, 1);
}
}
void TLightRWLock::WaitForUntrappedAndAcquireRead() {
if (AtomicFetchAdd(Counter_, -1) < 0)
goto skip_lock_try;
for (;;) {
again:
if (Y_UNLIKELY(AtomicFetchAdd(Counter_, 1) >= 0)) {
return;
} else {
if (AtomicFetchAdd(Counter_, -1) >= 0)
goto again;
}
skip_lock_try:
if (AtomicLoad(UnshareFutex_) && (AtomicLoad(Counter_) & 0x7FFFFFFF) == 0) {
SequenceStore(UnshareFutex_, 0);
FutexWake(UnshareFutex_, 1);
}
for (;;) {
for (ui32 i = 0; i < SpinCount_; ++i) {
SpinLockPause();
if (AtomicLoad(Counter_) >= 0)
goto again;
if (AtomicLoad(TrappedFutex_) == 1)
goto skip_store_trapped;
}
SequenceStore(TrappedFutex_, 1);
skip_store_trapped:
if (AtomicLoad(Counter_) < 0) {
FutexWait(TrappedFutex_, 1);
if (AtomicLoad(Counter_) < 0)
goto again;
} else if (AtomicLoad(TrappedFutex_)) {
SequenceStore(TrappedFutex_, 0);
FutexWake(TrappedFutex_, 0x7fffffff);
}
break;
}
}
}
#endif // _linux_
|