@@ -11,66 +11,43 @@ namespace NActors {
11
11
class TExecutorThread ;
12
12
class TBasicExecutorPool ;
13
13
14
- struct TExecutorThreadCtx {
15
- enum EWaitState : ui64 {
16
- WS_NONE,
17
- WS_ACTIVE,
18
- WS_BLOCKED,
19
- WS_RUNNING
20
- };
21
-
22
- struct TWaitState {
23
- EWaitState Flag = WS_NONE;
24
- ui32 NextPool = Max<ui32>();
25
-
26
- TWaitState () = default ;
27
-
28
- explicit TWaitState (ui64 state)
29
- : Flag(static_cast <EWaitState>(state & 0x7 ))
30
- , NextPool(state >> 3 )
31
- {}
32
-
33
- explicit TWaitState (EWaitState flag, ui32 nextPool = Max<ui32>())
34
- : Flag(flag)
35
- , NextPool(nextPool)
36
- {}
37
-
38
- explicit operator ui64 () {
39
- return Flag | ui64 (NextPool << 3 );
40
- }
41
- };
14
+ enum class EThreadState : ui64 {
15
+ None,
16
+ Spin,
17
+ Sleep,
18
+ Work
19
+ };
42
20
21
+ struct TGenericExecutorThreadCtx {
43
22
TAutoPtr<TExecutorThread> Thread;
44
23
TThreadParkPad WaitingPad;
45
24
46
25
private:
47
- std::atomic<ui64> WaitingFlag = WS_NONE ;
26
+ std::atomic<ui64> WaitingFlag = static_cast <ui64>(EThreadState::None) ;
48
27
49
28
public:
50
- TBasicExecutorPool *OwnerExecutorPool = nullptr ;
51
- std::atomic<TBasicExecutorPool*> OtherExecutorPool = nullptr ;
52
29
ui64 StartWakingTs = 0 ;
53
- ui32 NextPool = 0 ;
54
- bool IsShared;
55
-
56
- // different threads must spin/block on different cache-lines.
57
- // we add some padding bytes to enforce this rule;
58
30
31
+ template <typename TWaitState>
59
32
TWaitState GetState () {
60
33
return TWaitState (WaitingFlag.load ());
61
34
}
62
35
63
- TWaitState ExchangeState (EWaitState flag, ui32 nextPool = Max<ui32>()) {
64
- return TWaitState (WaitingFlag.exchange (static_cast <ui64>(TWaitState (flag, nextPool))));
36
+ template <typename TWaitState>
37
+ TWaitState ExchangeState (TWaitState state) {
38
+ return TWaitState (WaitingFlag.exchange (static_cast <ui64>(state)));
65
39
}
66
40
67
- bool ReplaceState (TWaitState &expected, EWaitState flag, ui32 nextPool = Max<ui32>()) {
41
+ template <typename TWaitState>
42
+ bool ReplaceState (TWaitState &expected, TWaitState state) {
68
43
ui64 expectedInt = static_cast <ui64>(expected);
69
- bool result = WaitingFlag.compare_exchange_strong (expectedInt, static_cast <ui64>(TWaitState (flag, nextPool) ));
44
+ bool result = WaitingFlag.compare_exchange_strong (expectedInt, static_cast <ui64>(state ));
70
45
expected = TWaitState (expectedInt);
71
46
return result;
72
47
}
73
48
49
+ protected:
50
+ template <typename TDerived, typename TWaitState>
74
51
void Spin (ui64 spinThresholdCycles, std::atomic<bool > *stopFlag) {
75
52
ui64 start = GetCycleCountFast ();
76
53
bool doSpin = true ;
@@ -81,11 +58,11 @@ namespace NActors {
81
58
break ;
82
59
}
83
60
for (ui32 i = 0 ; i < 12 ; ++i) {
84
- TWaitState state = GetState ();
85
- if (state. Flag == WS_ACTIVE ) {
61
+ TWaitState state = GetState<TWaitState> ();
62
+ if (static_cast <EThreadState>( state) == EThreadState::Spin ) {
86
63
SpinLockPause ();
87
64
} else {
88
- NextPool = state. NextPool ;
65
+ static_cast <TDerived*>( this )-> AfterWakeUp ( state) ;
89
66
doSpin = false ;
90
67
break ;
91
68
}
@@ -100,36 +77,101 @@ namespace NActors {
100
77
}
101
78
}
102
79
80
+ template <typename TDerived, typename TWaitState>
103
81
bool Sleep (std::atomic<bool > *stopFlag) {
104
82
Y_DEBUG_ABORT_UNLESS (TlsThreadContext);
105
83
106
- TWaitState state;
84
+ TWaitState state = TWaitState{EThreadState::Spin};
85
+ if (!ReplaceState<TWaitState>(state, TWaitState{EThreadState::Sleep})) {
86
+ static_cast <TDerived*>(this )->AfterWakeUp (state);
87
+ return false ;
88
+ }
89
+
107
90
do {
108
91
TlsThreadContext->Timers .HPNow = GetCycleCountFast ();
109
92
TlsThreadContext->Timers .Elapsed += TlsThreadContext->Timers .HPNow - TlsThreadContext->Timers .HPStart ;
110
93
if (WaitingPad.Park ()) // interrupted
111
94
return true ;
112
95
TlsThreadContext->Timers .HPStart = GetCycleCountFast ();
113
96
TlsThreadContext->Timers .Parked += TlsThreadContext->Timers .HPStart - TlsThreadContext->Timers .HPNow ;
114
- state = GetState ();
115
- } while (state.Flag == WS_BLOCKED && !stopFlag->load (std::memory_order_relaxed));
116
- NextPool = state.NextPool ;
97
+ state = GetState<TWaitState>();
98
+ } while (static_cast <EThreadState>(state) == EThreadState::Sleep && !stopFlag->load (std::memory_order_relaxed));
99
+
100
+ static_cast <TDerived*>(this )->AfterWakeUp (state);
117
101
return false ;
118
102
}
103
+ };
104
+
105
+ struct TExecutorThreadCtx : public TGenericExecutorThreadCtx {
106
+ using TBase = TGenericExecutorThreadCtx;
107
+
108
+ TBasicExecutorPool *OwnerExecutorPool = nullptr ;
109
+
110
+ void Spin (ui64 spinThresholdCycles, std::atomic<bool > *stopFlag) {
111
+ this ->TBase ::Spin<TExecutorThreadCtx, EThreadState>(spinThresholdCycles, stopFlag);
112
+ }
113
+
114
+ bool Sleep (std::atomic<bool > *stopFlag) {
115
+ return this ->TBase ::Sleep<TExecutorThreadCtx, EThreadState>(stopFlag);
116
+ }
119
117
120
118
bool Wait (ui64 spinThresholdCycles, std::atomic<bool > *stopFlag); // in executor_pool_basic.cpp
121
119
122
- bool Block (std::atomic<bool > *stopFlag) {
123
- TWaitState state{WS_ACTIVE};
124
- if (ReplaceState (state, WS_BLOCKED)) {
125
- Y_ABORT_UNLESS (state.Flag == WS_ACTIVE, " WaitingFlag# %d" , int (state.Flag ));
126
- return Sleep (stopFlag);
127
- } else {
128
- return false ;
129
- }
120
+ void AfterWakeUp (EThreadState /* state*/ ) {
130
121
}
131
122
132
123
TExecutorThreadCtx () = default ;
133
124
};
134
125
126
+
127
+ constexpr ui32 MaxPoolsForSharedThreads = 4 ;
128
+
129
+ struct TSharedExecutorThreadCtx : public TGenericExecutorThreadCtx {
130
+ using TBase = TGenericExecutorThreadCtx;
131
+
132
+ struct TWaitState {
133
+ EThreadState Flag = EThreadState::None;
134
+ ui32 NextPool = Max<ui32>();
135
+
136
+ TWaitState () = default ;
137
+
138
+ TWaitState (ui64 state)
139
+ : Flag(static_cast <EThreadState>(state & 0x7 ))
140
+ , NextPool(state >> 3 )
141
+ {}
142
+
143
+ TWaitState (EThreadState flag, ui32 nextPool = Max<ui32>())
144
+ : Flag(flag)
145
+ , NextPool(nextPool)
146
+ {}
147
+
148
+ explicit operator ui64 () {
149
+ return static_cast <ui64>(Flag) | ui64 (NextPool << 3 );
150
+ }
151
+
152
+ explicit operator EThreadState () {
153
+ return Flag;
154
+ }
155
+ };
156
+
157
+ std::atomic<TBasicExecutorPool*> ExecutorPools[MaxPoolsForSharedThreads];
158
+ ui32 NextPool = 0 ;
159
+
160
+ void AfterWakeUp (TWaitState state) {
161
+ NextPool = state.NextPool ;
162
+ }
163
+
164
+ void Spin (ui64 spinThresholdCycles, std::atomic<bool > *stopFlag) {
165
+ this ->TBase ::Spin<TSharedExecutorThreadCtx, TWaitState>(spinThresholdCycles, stopFlag);
166
+ }
167
+
168
+ bool Sleep (std::atomic<bool > *stopFlag) {
169
+ return this ->TBase ::Sleep<TSharedExecutorThreadCtx, TWaitState>(stopFlag);
170
+ }
171
+
172
+ bool Wait (ui64 spinThresholdCycles, std::atomic<bool > *stopFlag); // in executor_pool_basic.cpp
173
+
174
+ TSharedExecutorThreadCtx () = default ;
175
+ };
176
+
135
177
}
0 commit comments