aboutsummaryrefslogtreecommitdiff
path: root/src/linda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/linda.cpp')
-rw-r--r--src/linda.cpp464
1 files changed, 232 insertions, 232 deletions
diff --git a/src/linda.cpp b/src/linda.cpp
index 07911b3..fedcd01 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -59,8 +59,8 @@ Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_)
59Linda::~Linda() 59Linda::~Linda()
60{ 60{
61 if (std::holds_alternative<AllocatedName>(nameVariant)) { 61 if (std::holds_alternative<AllocatedName>(nameVariant)) {
62 AllocatedName& name = std::get<AllocatedName>(nameVariant); 62 AllocatedName& _name = std::get<AllocatedName>(nameVariant);
63 U->internalAllocator.free(name.name, name.len); 63 U->internalAllocator.free(_name.name, _name.len);
64 } 64 }
65} 65}
66 66
@@ -75,13 +75,13 @@ void Linda::setName(char const* name_, size_t len_)
75 ++len_; // don't forget terminating 0 75 ++len_; // don't forget terminating 0
76 if (len_ < kEmbeddedNameLength) { 76 if (len_ < kEmbeddedNameLength) {
77 nameVariant.emplace<EmbeddedName>(); 77 nameVariant.emplace<EmbeddedName>();
78 char* const name{ std::get<EmbeddedName>(nameVariant).data() }; 78 char* const _name{ std::get<EmbeddedName>(nameVariant).data() };
79 memcpy(name, name_, len_); 79 memcpy(_name, name_, len_);
80 } else { 80 } else {
81 AllocatedName& name = std::get<AllocatedName>(nameVariant); 81 AllocatedName& _name = std::get<AllocatedName>(nameVariant);
82 name.name = static_cast<char*>(U->internalAllocator.alloc(len_)); 82 _name.name = static_cast<char*>(U->internalAllocator.alloc(len_));
83 name.len = len_; 83 _name.len = len_;
84 memcpy(name.name, name_, len_); 84 memcpy(_name.name, name_, len_);
85 } 85 }
86} 86}
87 87
@@ -90,12 +90,12 @@ void Linda::setName(char const* name_, size_t len_)
90char const* Linda::getName() const 90char const* Linda::getName() const
91{ 91{
92 if (std::holds_alternative<AllocatedName>(nameVariant)) { 92 if (std::holds_alternative<AllocatedName>(nameVariant)) {
93 AllocatedName const& name = std::get<AllocatedName>(nameVariant); 93 AllocatedName const& _name = std::get<AllocatedName>(nameVariant);
94 return name.name; 94 return _name.name;
95 } 95 }
96 if (std::holds_alternative<EmbeddedName>(nameVariant)) { 96 if (std::holds_alternative<EmbeddedName>(nameVariant)) {
97 char const* const name{ std::get<EmbeddedName>(nameVariant).data() }; 97 char const* const _name{ std::get<EmbeddedName>(nameVariant).data() };
98 return name; 98 return _name;
99 } 99 }
100 return nullptr; 100 return nullptr;
101} 101}
@@ -105,20 +105,20 @@ char const* Linda::getName() const
105template <bool OPT> 105template <bool OPT>
106[[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_) 106[[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_)
107{ 107{
108 Linda* const linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) }; 108 Linda* const _linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) };
109 if constexpr (!OPT) { 109 if constexpr (!OPT) {
110 luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr 110 luaL_argcheck(L_, _linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr
111 LUA_ASSERT(L_, linda->U == universe_get(L_)); 111 LUA_ASSERT(L_, _linda->U == universe_get(L_));
112 } 112 }
113 return linda; 113 return _linda;
114} 114}
115 115
116// ################################################################################################# 116// #################################################################################################
117 117
118static void check_key_types(lua_State* L_, int start_, int end_) 118static void check_key_types(lua_State* L_, int start_, int end_)
119{ 119{
120 for (int i{ start_ }; i <= end_; ++i) { 120 for (int _i{ start_ }; _i <= end_; ++_i) {
121 LuaType const t{ lua_type_as_enum(L_, i) }; 121 LuaType const t{ lua_type_as_enum(L_, _i) };
122 switch (t) { 122 switch (t) {
123 case LuaType::BOOLEAN: 123 case LuaType::BOOLEAN:
124 case LuaType::NUMBER: 124 case LuaType::NUMBER:
@@ -128,14 +128,14 @@ static void check_key_types(lua_State* L_, int start_, int end_)
128 case LuaType::LIGHTUSERDATA: 128 case LuaType::LIGHTUSERDATA:
129 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; 129 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel };
130 for (UniqueKey const& key : kKeysToCheck) { 130 for (UniqueKey const& key : kKeysToCheck) {
131 if (key.equals(L_, i)) { 131 if (key.equals(L_, _i)) {
132 raise_luaL_error(L_, "argument #%d: can't use %s as a key", i, key.debugName); 132 raise_luaL_error(L_, "argument #%d: can't use %s as a key", _i, key.debugName);
133 break; 133 break;
134 } 134 }
135 } 135 }
136 break; 136 break;
137 } 137 }
138 raise_luaL_error(L_, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i); 138 raise_luaL_error(L_, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", _i);
139 } 139 }
140} 140}
141 141
@@ -144,29 +144,29 @@ static void check_key_types(lua_State* L_, int start_, int end_)
144// used to perform all linda operations that access keepers 144// used to perform all linda operations that access keepers
145int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) 145int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_)
146{ 146{
147 Linda* const linda{ ToLinda<false>(L_, 1) }; 147 Linda* const _linda{ ToLinda<false>(L_, 1) };
148 148
149 // acquire the keeper 149 // acquire the keeper
150 Keeper* const K{ linda->acquireKeeper() }; 150 Keeper* const _K{ _linda->acquireKeeper() };
151 lua_State* const KL{ K ? K->L : nullptr }; 151 lua_State* const _KL{ _K ? _K->L : nullptr };
152 if (KL == nullptr) 152 if (_KL == nullptr)
153 return 0; 153 return 0;
154 // if we didn't do anything wrong, the keeper stack should be clean 154 // if we didn't do anything wrong, the keeper stack should be clean
155 LUA_ASSERT(L_, lua_gettop(KL) == 0); 155 LUA_ASSERT(L_, lua_gettop(_KL) == 0);
156 156
157 // push the function to be called and move it before the arguments 157 // push the function to be called and move it before the arguments
158 lua_pushcfunction(L_, f_); 158 lua_pushcfunction(L_, f_);
159 lua_insert(L_, 1); 159 lua_insert(L_, 1);
160 // do a protected call 160 // do a protected call
161 int const rc{ lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0) }; 161 int const _rc{ lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0) };
162 // whatever happens, the keeper state stack must be empty when we are done 162 // whatever happens, the keeper state stack must be empty when we are done
163 lua_settop(KL, 0); 163 lua_settop(_KL, 0);
164 164
165 // release the keeper 165 // release the keeper
166 linda->releaseKeeper(K); 166 _linda->releaseKeeper(_K);
167 167
168 // if there was an error, forward it 168 // if there was an error, forward it
169 if (rc != LUA_OK) { 169 if (_rc != LUA_OK) {
170 raise_lua_error(L_); 170 raise_lua_error(L_);
171 } 171 }
172 // return whatever the actual operation provided 172 // return whatever the actual operation provided
@@ -186,108 +186,108 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_)
186 */ 186 */
187LUAG_FUNC(linda_send) 187LUAG_FUNC(linda_send)
188{ 188{
189 auto send = [](lua_State* L_) { 189 auto _send = [](lua_State* L_) {
190 Linda* const linda{ ToLinda<false>(L_, 1) }; 190 Linda* const _linda{ ToLinda<false>(L_, 1) };
191 int key_i{ 2 }; // index of first key, if timeout not there 191 int _key_i{ 2 }; // index of first key, if timeout not there
192 192
193 std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 193 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
194 if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion 194 if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion
195 lua_Duration const duration{ lua_tonumber(L_, 2) }; 195 lua_Duration const _duration{ lua_tonumber(L_, 2) };
196 if (duration.count() >= 0.0) { 196 if (_duration.count() >= 0.0) {
197 until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); 197 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
198 } else { 198 } else {
199 raise_luaL_argerror(L_, 2, "duration cannot be < 0"); 199 raise_luaL_argerror(L_, 2, "duration cannot be < 0");
200 } 200 }
201 ++key_i; 201 ++_key_i;
202 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key 202 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key
203 ++key_i; 203 ++_key_i;
204 } 204 }
205 205
206 // make sure the key is of a valid type 206 // make sure the key is of a valid type
207 check_key_types(L_, key_i, key_i); 207 check_key_types(L_, _key_i, _key_i);
208 208
209 STACK_GROW(L_, 1); 209 STACK_GROW(L_, 1);
210 210
211 // make sure there is something to send 211 // make sure there is something to send
212 if (lua_gettop(L_) == key_i) { 212 if (lua_gettop(L_) == _key_i) {
213 raise_luaL_error(L_, "no data to send"); 213 raise_luaL_error(L_, "no data to send");
214 } 214 }
215 215
216 // convert nils to some special non-nil sentinel in sent values 216 // convert nils to some special non-nil sentinel in sent values
217 keeper_toggle_nil_sentinels(L_, key_i + 1, LookupMode::ToKeeper); 217 keeper_toggle_nil_sentinels(L_, _key_i + 1, LookupMode::ToKeeper);
218 bool ret{ false }; 218 bool _ret{ false };
219 CancelRequest cancel{ CancelRequest::None }; 219 CancelRequest _cancel{ CancelRequest::None };
220 KeeperCallResult pushed; 220 KeeperCallResult _pushed;
221 { 221 {
222 Lane* const lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; 222 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
223 Keeper* const K{ linda->whichKeeper() }; 223 Keeper* const _K{ _linda->whichKeeper() };
224 KeeperState const KL{ K ? K->L : nullptr }; 224 KeeperState const _KL{ _K ? _K->L : nullptr };
225 if (KL == nullptr) 225 if (_KL == nullptr)
226 return 0; 226 return 0;
227 227
228 STACK_CHECK_START_REL(KL, 0); 228 STACK_CHECK_START_REL(_KL, 0);
229 for (bool try_again{ true };;) { 229 for (bool _try_again{ true };;) {
230 if (lane != nullptr) { 230 if (_lane != nullptr) {
231 cancel = lane->cancelRequest; 231 _cancel = _lane->cancelRequest;
232 } 232 }
233 cancel = (cancel != CancelRequest::None) ? cancel : linda->cancelRequest; 233 _cancel = (_cancel != CancelRequest::None) ? _cancel : _linda->cancelRequest;
234 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything 234 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
235 if (!try_again || cancel != CancelRequest::None) { 235 if (!_try_again || _cancel != CancelRequest::None) {
236 pushed.emplace(0); 236 _pushed.emplace(0);
237 break; 237 break;
238 } 238 }
239 239
240 STACK_CHECK(KL, 0); 240 STACK_CHECK(_KL, 0);
241 pushed = keeper_call(linda->U, KL, KEEPER_API(send), L_, linda, key_i); 241 _pushed = keeper_call(_KL, KEEPER_API(send), L_, _linda, _key_i);
242 if (!pushed.has_value()) { 242 if (!_pushed.has_value()) {
243 break; 243 break;
244 } 244 }
245 LUA_ASSERT(L_, pushed.value() == 1); 245 LUA_ASSERT(L_, _pushed.value() == 1);
246 246
247 ret = lua_toboolean(L_, -1) ? true : false; 247 _ret = lua_toboolean(L_, -1) ? true : false;
248 lua_pop(L_, 1); 248 lua_pop(L_, 1);
249 249
250 if (ret) { 250 if (_ret) {
251 // Wake up ALL waiting threads 251 // Wake up ALL waiting threads
252 linda->writeHappened.notify_all(); 252 _linda->writeHappened.notify_all();
253 break; 253 break;
254 } 254 }
255 255
256 // instant timout to bypass the wait syscall 256 // instant timout to bypass the wait syscall
257 if (std::chrono::steady_clock::now() >= until) { 257 if (std::chrono::steady_clock::now() >= _until) {
258 break; /* no wait; instant timeout */ 258 break; /* no wait; instant timeout */
259 } 259 }
260 260
261 // storage limit hit, wait until timeout or signalled that we should try again 261 // storage limit hit, wait until timeout or signalled that we should try again
262 { 262 {
263 Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings 263 Lane::Status _prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings
264 if (lane != nullptr) { 264 if (_lane != nullptr) {
265 // change status of lane to "waiting" 265 // change status of lane to "waiting"
266 prev_status = lane->status; // Running, most likely 266 _prev_status = _lane->status; // Running, most likely
267 LUA_ASSERT(L_, prev_status == Lane::Running); // but check, just in case 267 LUA_ASSERT(L_, _prev_status == Lane::Running); // but check, just in case
268 lane->status = Lane::Waiting; 268 _lane->status = Lane::Waiting;
269 LUA_ASSERT(L_, lane->waiting_on == nullptr); 269 LUA_ASSERT(L_, _lane->waiting_on == nullptr);
270 lane->waiting_on = &linda->readHappened; 270 _lane->waiting_on = &_linda->readHappened;
271 } 271 }
272 // could not send because no room: wait until some data was read before trying again, or until timeout is reached 272 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
273 std::unique_lock<std::mutex> keeper_lock{ K->mutex, std::adopt_lock }; 273 std::unique_lock<std::mutex> _keeper_lock{ _K->mutex, std::adopt_lock };
274 std::cv_status const status{ linda->readHappened.wait_until(keeper_lock, until) }; 274 std::cv_status const status{ _linda->readHappened.wait_until(_keeper_lock, _until) };
275 keeper_lock.release(); // we don't want to release the lock! 275 _keeper_lock.release(); // we don't want to release the lock!
276 try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups 276 _try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups
277 if (lane != nullptr) { 277 if (_lane != nullptr) {
278 lane->waiting_on = nullptr; 278 _lane->waiting_on = nullptr;
279 lane->status = prev_status; 279 _lane->status = _prev_status;
280 } 280 }
281 } 281 }
282 } 282 }
283 STACK_CHECK(KL, 0); 283 STACK_CHECK(_KL, 0);
284 } 284 }
285 285
286 if (!pushed.has_value()) { 286 if (!_pushed.has_value()) {
287 raise_luaL_error(L_, "tried to copy unsupported types"); 287 raise_luaL_error(L_, "tried to copy unsupported types");
288 } 288 }
289 289
290 switch (cancel) { 290 switch (_cancel) {
291 case CancelRequest::Soft: 291 case CancelRequest::Soft:
292 // if user wants to soft-cancel, the call returns lanes.cancel_error 292 // if user wants to soft-cancel, the call returns lanes.cancel_error
293 kCancelError.pushKey(L_); 293 kCancelError.pushKey(L_);
@@ -298,11 +298,11 @@ LUAG_FUNC(linda_send)
298 raise_cancel_error(L_); // raises an error and doesn't return 298 raise_cancel_error(L_); // raises an error and doesn't return
299 299
300 default: 300 default:
301 lua_pushboolean(L_, ret); // true (success) or false (timeout) 301 lua_pushboolean(L_, _ret); // true (success) or false (timeout)
302 return 1; 302 return 1;
303 } 303 }
304 }; 304 };
305 return Linda::ProtectedCall(L_, send); 305 return Linda::ProtectedCall(L_, _send);
306} 306}
307 307
308// ################################################################################################# 308// #################################################################################################
@@ -320,122 +320,122 @@ LUAG_FUNC(linda_send)
320 */ 320 */
321LUAG_FUNC(linda_receive) 321LUAG_FUNC(linda_receive)
322{ 322{
323 auto receive = [](lua_State* L_) { 323 auto _receive = [](lua_State* L_) {
324 Linda* const linda{ ToLinda<false>(L_, 1) }; 324 Linda* const _linda{ ToLinda<false>(L_, 1) };
325 int key_i{ 2 }; // index of first key, if timeout not there 325 int _key_i{ 2 }; // index of first key, if timeout not there
326 326
327 std::chrono::time_point<std::chrono::steady_clock> until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 327 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
328 if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion 328 if (lua_type(L_, 2) == LUA_TNUMBER) { // we don't want to use lua_isnumber() because of autocoercion
329 lua_Duration const duration{ lua_tonumber(L_, 2) }; 329 lua_Duration const _duration{ lua_tonumber(L_, 2) };
330 if (duration.count() >= 0.0) { 330 if (_duration.count() >= 0.0) {
331 until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); 331 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
332 } else { 332 } else {
333 raise_luaL_argerror(L_, 2, "duration cannot be < 0"); 333 raise_luaL_argerror(L_, 2, "duration cannot be < 0");
334 } 334 }
335 ++key_i; 335 ++_key_i;
336 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key 336 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key
337 ++key_i; 337 ++_key_i;
338 } 338 }
339 339
340 keeper_api_t selected_keeper_receive{ nullptr }; 340 keeper_api_t _selected_keeper_receive{ nullptr };
341 int expected_pushed_min{ 0 }, expected_pushed_max{ 0 }; 341 int _expected_pushed_min{ 0 }, _expected_pushed_max{ 0 };
342 // are we in batched mode? 342 // are we in batched mode?
343 kLindaBatched.pushKey(L_); 343 kLindaBatched.pushKey(L_);
344 int const is_batched{ lua501_equal(L_, key_i, -1) }; 344 int const _is_batched{ lua501_equal(L_, _key_i, -1) };
345 lua_pop(L_, 1); 345 lua_pop(L_, 1);
346 if (is_batched) { 346 if (_is_batched) {
347 // no need to pass linda.batched in the keeper state 347 // no need to pass linda.batched in the keeper state
348 ++key_i; 348 ++_key_i;
349 // make sure the keys are of a valid type 349 // make sure the keys are of a valid type
350 check_key_types(L_, key_i, key_i); 350 check_key_types(L_, _key_i, _key_i);
351 // receive multiple values from a single slot 351 // receive multiple values from a single slot
352 selected_keeper_receive = KEEPER_API(receive_batched); 352 _selected_keeper_receive = KEEPER_API(receive_batched);
353 // we expect a user-defined amount of return value 353 // we expect a user-defined amount of return value
354 expected_pushed_min = (int) luaL_checkinteger(L_, key_i + 1); 354 _expected_pushed_min = (int) luaL_checkinteger(L_, _key_i + 1);
355 expected_pushed_max = (int) luaL_optinteger(L_, key_i + 2, expected_pushed_min); 355 _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min);
356 // don't forget to count the key in addition to the values 356 // don't forget to count the key in addition to the values
357 ++expected_pushed_min; 357 ++_expected_pushed_min;
358 ++expected_pushed_max; 358 ++_expected_pushed_max;
359 if (expected_pushed_min > expected_pushed_max) { 359 if (_expected_pushed_min > _expected_pushed_max) {
360 raise_luaL_error(L_, "batched min/max error"); 360 raise_luaL_error(L_, "batched min/max error");
361 } 361 }
362 } else { 362 } else {
363 // make sure the keys are of a valid type 363 // make sure the keys are of a valid type
364 check_key_types(L_, key_i, lua_gettop(L_)); 364 check_key_types(L_, _key_i, lua_gettop(L_));
365 // receive a single value, checking multiple slots 365 // receive a single value, checking multiple slots
366 selected_keeper_receive = KEEPER_API(receive); 366 _selected_keeper_receive = KEEPER_API(receive);
367 // we expect a single (value, key) pair of returned values 367 // we expect a single (value, key) pair of returned values
368 expected_pushed_min = expected_pushed_max = 2; 368 _expected_pushed_min = _expected_pushed_max = 2;
369 } 369 }
370 370
371 Lane* const lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) }; 371 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
372 Keeper* const K{ linda->whichKeeper() }; 372 Keeper* const _K{ _linda->whichKeeper() };
373 KeeperState const KL{ K ? K->L : nullptr }; 373 KeeperState const _KL{ _K ? _K->L : nullptr };
374 if (KL == nullptr) 374 if (_KL == nullptr)
375 return 0; 375 return 0;
376 376
377 CancelRequest cancel{ CancelRequest::None }; 377 CancelRequest _cancel{ CancelRequest::None };
378 KeeperCallResult pushed; 378 KeeperCallResult _pushed;
379 STACK_CHECK_START_REL(KL, 0); 379 STACK_CHECK_START_REL(_KL, 0);
380 for (bool try_again{ true };;) { 380 for (bool _try_again{ true };;) {
381 if (lane != nullptr) { 381 if (_lane != nullptr) {
382 cancel = lane->cancelRequest; 382 _cancel = _lane->cancelRequest;
383 } 383 }
384 cancel = (cancel != CancelRequest::None) ? cancel : linda->cancelRequest; 384 _cancel = (_cancel != CancelRequest::None) ? _cancel : _linda->cancelRequest;
385 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything 385 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
386 if (!try_again || cancel != CancelRequest::None) { 386 if (!_try_again || _cancel != CancelRequest::None) {
387 pushed.emplace(0); 387 _pushed.emplace(0);
388 break; 388 break;
389 } 389 }
390 390
391 // all arguments of receive() but the first are passed to the keeper's receive function 391 // all arguments of receive() but the first are passed to the keeper's receive function
392 pushed = keeper_call(linda->U, KL, selected_keeper_receive, L_, linda, key_i); 392 _pushed = keeper_call(_KL, _selected_keeper_receive, L_, _linda, _key_i);
393 if (!pushed.has_value()) { 393 if (!_pushed.has_value()) {
394 break; 394 break;
395 } 395 }
396 if (pushed.value() > 0) { 396 if (_pushed.value() > 0) {
397 LUA_ASSERT(L_, pushed.value() >= expected_pushed_min && pushed.value() <= expected_pushed_max); 397 LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max);
398 // replace sentinels with real nils 398 // replace sentinels with real nils
399 keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - pushed.value(), LookupMode::FromKeeper); 399 keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - _pushed.value(), LookupMode::FromKeeper);
400 // To be done from within the 'K' locking area 400 // To be done from within the 'K' locking area
401 // 401 //
402 linda->readHappened.notify_all(); 402 _linda->readHappened.notify_all();
403 break; 403 break;
404 } 404 }
405 405
406 if (std::chrono::steady_clock::now() >= until) { 406 if (std::chrono::steady_clock::now() >= _until) {
407 break; /* instant timeout */ 407 break; /* instant timeout */
408 } 408 }
409 409
410 // nothing received, wait until timeout or signalled that we should try again 410 // nothing received, wait until timeout or signalled that we should try again
411 { 411 {
412 Lane::Status prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings 412 Lane::Status _prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings
413 if (lane != nullptr) { 413 if (_lane != nullptr) {
414 // change status of lane to "waiting" 414 // change status of lane to "waiting"
415 prev_status = lane->status; // Running, most likely 415 _prev_status = _lane->status; // Running, most likely
416 LUA_ASSERT(L_, prev_status == Lane::Running); // but check, just in case 416 LUA_ASSERT(L_, _prev_status == Lane::Running); // but check, just in case
417 lane->status = Lane::Waiting; 417 _lane->status = Lane::Waiting;
418 LUA_ASSERT(L_, lane->waiting_on == nullptr); 418 LUA_ASSERT(L_, _lane->waiting_on == nullptr);
419 lane->waiting_on = &linda->writeHappened; 419 _lane->waiting_on = &_linda->writeHappened;
420 } 420 }
421 // not enough data to read: wakeup when data was sent, or when timeout is reached 421 // not enough data to read: wakeup when data was sent, or when timeout is reached
422 std::unique_lock<std::mutex> keeper_lock{ K->mutex, std::adopt_lock }; 422 std::unique_lock<std::mutex> _keeper_lock{ _K->mutex, std::adopt_lock };
423 std::cv_status const status{ linda->writeHappened.wait_until(keeper_lock, until) }; 423 std::cv_status const _status{ _linda->writeHappened.wait_until(_keeper_lock, _until) };
424 keeper_lock.release(); // we don't want to release the lock! 424 _keeper_lock.release(); // we don't want to release the lock!
425 try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups 425 _try_again = (_status == std::cv_status::no_timeout); // detect spurious wakeups
426 if (lane != nullptr) { 426 if (_lane != nullptr) {
427 lane->waiting_on = nullptr; 427 _lane->waiting_on = nullptr;
428 lane->status = prev_status; 428 _lane->status = _prev_status;
429 } 429 }
430 } 430 }
431 } 431 }
432 STACK_CHECK(KL, 0); 432 STACK_CHECK(_KL, 0);
433 433
434 if (!pushed.has_value()) { 434 if (!_pushed.has_value()) {
435 raise_luaL_error(L_, "tried to copy unsupported types"); 435 raise_luaL_error(L_, "tried to copy unsupported types");
436 } 436 }
437 437
438 switch (cancel) { 438 switch (_cancel) {
439 case CancelRequest::Soft: 439 case CancelRequest::Soft:
440 // if user wants to soft-cancel, the call returns kCancelError 440 // if user wants to soft-cancel, the call returns kCancelError
441 kCancelError.pushKey(L_); 441 kCancelError.pushKey(L_);
@@ -446,10 +446,10 @@ LUAG_FUNC(linda_receive)
446 raise_cancel_error(L_); // raises an error and doesn't return 446 raise_cancel_error(L_); // raises an error and doesn't return
447 447
448 default: 448 default:
449 return pushed.value(); 449 return _pushed.value();
450 } 450 }
451 }; 451 };
452 return Linda::ProtectedCall(L_, receive); 452 return Linda::ProtectedCall(L_, _receive);
453} 453}
454 454
455// ################################################################################################# 455// #################################################################################################
@@ -465,40 +465,40 @@ LUAG_FUNC(linda_receive)
465LUAG_FUNC(linda_set) 465LUAG_FUNC(linda_set)
466{ 466{
467 auto set = [](lua_State* L_) { 467 auto set = [](lua_State* L_) {
468 Linda* const linda{ ToLinda<false>(L_, 1) }; 468 Linda* const _linda{ ToLinda<false>(L_, 1) };
469 bool const has_value{ lua_gettop(L_) > 2 }; 469 bool const _has_value{ lua_gettop(L_) > 2 };
470 // make sure the key is of a valid type (throws an error if not the case) 470 // make sure the key is of a valid type (throws an error if not the case)
471 check_key_types(L_, 2, 2); 471 check_key_types(L_, 2, 2);
472 472
473 Keeper* const K{ linda->whichKeeper() }; 473 Keeper* const _K{ _linda->whichKeeper() };
474 KeeperCallResult pushed; 474 KeeperCallResult _pushed;
475 if (linda->cancelRequest == CancelRequest::None) { 475 if (_linda->cancelRequest == CancelRequest::None) {
476 if (has_value) { 476 if (_has_value) {
477 // convert nils to some special non-nil sentinel in sent values 477 // convert nils to some special non-nil sentinel in sent values
478 keeper_toggle_nil_sentinels(L_, 3, LookupMode::ToKeeper); 478 keeper_toggle_nil_sentinels(L_, 3, LookupMode::ToKeeper);
479 } 479 }
480 pushed = keeper_call(linda->U, K->L, KEEPER_API(set), L_, linda, 2); 480 _pushed = keeper_call(_K->L, KEEPER_API(set), L_, _linda, 2);
481 if (pushed.has_value()) { // no error? 481 if (_pushed.has_value()) { // no error?
482 LUA_ASSERT(L_, pushed.value() == 0 || pushed.value() == 1); 482 LUA_ASSERT(L_, _pushed.value() == 0 || _pushed.value() == 1);
483 483
484 if (has_value) { 484 if (_has_value) {
485 // we put some data in the slot, tell readers that they should wake 485 // we put some data in the slot, tell readers that they should wake
486 linda->writeHappened.notify_all(); // To be done from within the 'K' locking area 486 _linda->writeHappened.notify_all(); // To be done from within the 'K' locking area
487 } 487 }
488 if (pushed.value() == 1) { 488 if (_pushed.value() == 1) {
489 // the key was full, but it is no longer the case, tell writers they should wake 489 // the key was full, but it is no longer the case, tell writers they should wake
490 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1); 490 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1);
491 linda->readHappened.notify_all(); // To be done from within the 'K' locking area 491 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area
492 } 492 }
493 } 493 }
494 } else { // linda is cancelled 494 } else { // linda is cancelled
495 // do nothing and return lanes.cancel_error 495 // do nothing and return lanes.cancel_error
496 kCancelError.pushKey(L_); 496 kCancelError.pushKey(L_);
497 pushed.emplace(1); 497 _pushed.emplace(1);
498 } 498 }
499 499
500 // must trigger any error after keeper state has been released 500 // must trigger any error after keeper state has been released
501 return OptionalValue(pushed, L_, "tried to copy unsupported types"); 501 return OptionalValue(_pushed, L_, "tried to copy unsupported types");
502 }; 502 };
503 return Linda::ProtectedCall(L_, set); 503 return Linda::ProtectedCall(L_, set);
504} 504}
@@ -512,16 +512,16 @@ LUAG_FUNC(linda_set)
512 */ 512 */
513LUAG_FUNC(linda_count) 513LUAG_FUNC(linda_count)
514{ 514{
515 auto count = [](lua_State* L_) { 515 auto _count = [](lua_State* L_) {
516 Linda* const linda{ ToLinda<false>(L_, 1) }; 516 Linda* const _linda{ ToLinda<false>(L_, 1) };
517 // make sure the keys are of a valid type 517 // make sure the keys are of a valid type
518 check_key_types(L_, 2, lua_gettop(L_)); 518 check_key_types(L_, 2, lua_gettop(L_));
519 519
520 Keeper* const K{ linda->whichKeeper() }; 520 Keeper* const _K{ _linda->whichKeeper() };
521 KeeperCallResult const pushed{ keeper_call(linda->U, K->L, KEEPER_API(count), L_, linda, 2) }; 521 KeeperCallResult const _pushed{ keeper_call(_K->L, KEEPER_API(count), L_, _linda, 2) };
522 return OptionalValue(pushed, L_, "tried to count an invalid key"); 522 return OptionalValue(_pushed, L_, "tried to count an invalid key");
523 }; 523 };
524 return Linda::ProtectedCall(L_, count); 524 return Linda::ProtectedCall(L_, _count);
525} 525}
526 526
527// ################################################################################################# 527// #################################################################################################
@@ -534,27 +534,27 @@ LUAG_FUNC(linda_count)
534LUAG_FUNC(linda_get) 534LUAG_FUNC(linda_get)
535{ 535{
536 auto get = [](lua_State* L_) { 536 auto get = [](lua_State* L_) {
537 Linda* const linda{ ToLinda<false>(L_, 1) }; 537 Linda* const _linda{ ToLinda<false>(L_, 1) };
538 lua_Integer const count{ luaL_optinteger(L_, 3, 1) }; 538 lua_Integer const _count{ luaL_optinteger(L_, 3, 1) };
539 luaL_argcheck(L_, count >= 1, 3, "count should be >= 1"); 539 luaL_argcheck(L_, _count >= 1, 3, "count should be >= 1");
540 luaL_argcheck(L_, lua_gettop(L_) <= 3, 4, "too many arguments"); 540 luaL_argcheck(L_, lua_gettop(L_) <= 3, 4, "too many arguments");
541 // make sure the key is of a valid type (throws an error if not the case) 541 // make sure the key is of a valid type (throws an error if not the case)
542 check_key_types(L_, 2, 2); 542 check_key_types(L_, 2, 2);
543 543
544 KeeperCallResult pushed; 544 KeeperCallResult _pushed;
545 if (linda->cancelRequest == CancelRequest::None) { 545 if (_linda->cancelRequest == CancelRequest::None) {
546 Keeper* const K{ linda->whichKeeper() }; 546 Keeper* const _K{ _linda->whichKeeper() };
547 pushed = keeper_call(linda->U, K->L, KEEPER_API(get), L_, linda, 2); 547 _pushed = keeper_call(_K->L, KEEPER_API(get), L_, _linda, 2);
548 if (pushed.value_or(0) > 0) { 548 if (_pushed.value_or(0) > 0) {
549 keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - pushed.value(), LookupMode::FromKeeper); 549 keeper_toggle_nil_sentinels(L_, lua_gettop(L_) - _pushed.value(), LookupMode::FromKeeper);
550 } 550 }
551 } else { // linda is cancelled 551 } else { // linda is cancelled
552 // do nothing and return lanes.cancel_error 552 // do nothing and return lanes.cancel_error
553 kCancelError.pushKey(L_); 553 kCancelError.pushKey(L_);
554 pushed.emplace(1); 554 _pushed.emplace(1);
555 } 555 }
556 // an error can be raised if we attempt to read an unregistered function 556 // an error can be raised if we attempt to read an unregistered function
557 return OptionalValue(pushed, L_, "tried to copy unsupported types"); 557 return OptionalValue(_pushed, L_, "tried to copy unsupported types");
558 }; 558 };
559 return Linda::ProtectedCall(L_, get); 559 return Linda::ProtectedCall(L_, get);
560} 560}
@@ -569,8 +569,8 @@ LUAG_FUNC(linda_get)
569 */ 569 */
570LUAG_FUNC(linda_limit) 570LUAG_FUNC(linda_limit)
571{ 571{
572 auto limit = [](lua_State* L_) { 572 auto _limit = [](lua_State* L_) {
573 Linda* const linda{ ToLinda<false>(L_, 1) }; 573 Linda* const _linda{ ToLinda<false>(L_, 1) };
574 // make sure we got 3 arguments: the linda, a key and a limit 574 // make sure we got 3 arguments: the linda, a key and a limit
575 luaL_argcheck(L_, lua_gettop(L_) == 3, 2, "wrong number of arguments"); 575 luaL_argcheck(L_, lua_gettop(L_) == 3, 2, "wrong number of arguments");
576 // make sure we got a numeric limit 576 // make sure we got a numeric limit
@@ -578,24 +578,24 @@ LUAG_FUNC(linda_limit)
578 // make sure the key is of a valid type 578 // make sure the key is of a valid type
579 check_key_types(L_, 2, 2); 579 check_key_types(L_, 2, 2);
580 580
581 KeeperCallResult pushed; 581 KeeperCallResult _pushed;
582 if (linda->cancelRequest == CancelRequest::None) { 582 if (_linda->cancelRequest == CancelRequest::None) {
583 Keeper* const K{ linda->whichKeeper() }; 583 Keeper* const _K{ _linda->whichKeeper() };
584 pushed = keeper_call(linda->U, K->L, KEEPER_API(limit), L_, linda, 2); 584 _pushed = keeper_call(_K->L, KEEPER_API(limit), L_, _linda, 2);
585 LUA_ASSERT(L_, pushed.has_value() && (pushed.value() == 0 || pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads 585 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 0 || _pushed.value() == 1)); // no error, optional boolean value saying if we should wake blocked writer threads
586 if (pushed.value() == 1) { 586 if (_pushed.value() == 1) {
587 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1); 587 LUA_ASSERT(L_, lua_type(L_, -1) == LUA_TBOOLEAN && lua_toboolean(L_, -1) == 1);
588 linda->readHappened.notify_all(); // To be done from within the 'K' locking area 588 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area
589 } 589 }
590 } else { // linda is cancelled 590 } else { // linda is cancelled
591 // do nothing and return lanes.cancel_error 591 // do nothing and return lanes.cancel_error
592 kCancelError.pushKey(L_); 592 kCancelError.pushKey(L_);
593 pushed.emplace(1); 593 _pushed.emplace(1);
594 } 594 }
595 // propagate pushed boolean if any 595 // propagate pushed boolean if any
596 return pushed.value(); 596 return _pushed.value();
597 }; 597 };
598 return Linda::ProtectedCall(L_, limit); 598 return Linda::ProtectedCall(L_, _limit);
599} 599}
600 600
601// ################################################################################################# 601// #################################################################################################
@@ -607,23 +607,23 @@ LUAG_FUNC(linda_limit)
607 */ 607 */
608LUAG_FUNC(linda_cancel) 608LUAG_FUNC(linda_cancel)
609{ 609{
610 Linda* const linda{ ToLinda<false>(L_, 1) }; 610 Linda* const _linda{ ToLinda<false>(L_, 1) };
611 char const* who = luaL_optstring(L_, 2, "both"); 611 char const* _who{ luaL_optstring(L_, 2, "both") };
612 // make sure we got 3 arguments: the linda, a key and a limit 612 // make sure we got 3 arguments: the linda, a key and a limit
613 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); 613 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments");
614 614
615 linda->cancelRequest = CancelRequest::Soft; 615 _linda->cancelRequest = CancelRequest::Soft;
616 if (strcmp(who, "both") == 0) { // tell everyone writers to wake up 616 if (strcmp(_who, "both") == 0) { // tell everyone writers to wake up
617 linda->writeHappened.notify_all(); 617 _linda->writeHappened.notify_all();
618 linda->readHappened.notify_all(); 618 _linda->readHappened.notify_all();
619 } else if (strcmp(who, "none") == 0) { // reset flag 619 } else if (strcmp(_who, "none") == 0) { // reset flag
620 linda->cancelRequest = CancelRequest::None; 620 _linda->cancelRequest = CancelRequest::None;
621 } else if (strcmp(who, "read") == 0) { // tell blocked readers to wake up 621 } else if (strcmp(_who, "read") == 0) { // tell blocked readers to wake up
622 linda->writeHappened.notify_all(); 622 _linda->writeHappened.notify_all();
623 } else if (strcmp(who, "write") == 0) { // tell blocked writers to wake up 623 } else if (strcmp(_who, "write") == 0) { // tell blocked writers to wake up
624 linda->readHappened.notify_all(); 624 _linda->readHappened.notify_all();
625 } else { 625 } else {
626 raise_luaL_error(L_, "unknown wake hint '%s'", who); 626 raise_luaL_error(L_, "unknown wake hint '%s'", _who);
627 } 627 }
628 return 0; 628 return 0;
629} 629}
@@ -642,8 +642,8 @@ LUAG_FUNC(linda_cancel)
642 */ 642 */
643LUAG_FUNC(linda_deep) 643LUAG_FUNC(linda_deep)
644{ 644{
645 Linda* const linda{ ToLinda<false>(L_, 1) }; 645 Linda* const _linda{ ToLinda<false>(L_, 1) };
646 lua_pushlightuserdata(L_, linda); // just the address 646 lua_pushlightuserdata(L_, _linda); // just the address
647 return 1; 647 return 1;
648} 648}
649 649
@@ -660,15 +660,15 @@ LUAG_FUNC(linda_deep)
660template <bool OPT> 660template <bool OPT>
661[[nodiscard]] static int LindaToString(lua_State* L_, int idx_) 661[[nodiscard]] static int LindaToString(lua_State* L_, int idx_)
662{ 662{
663 Linda* const linda{ ToLinda<OPT>(L_, idx_) }; 663 Linda* const _linda{ ToLinda<OPT>(L_, idx_) };
664 if (linda != nullptr) { 664 if (_linda != nullptr) {
665 char text[128]; 665 char _text[128];
666 int len; 666 int _len;
667 if (linda->getName()) 667 if (_linda->getName())
668 len = sprintf(text, "Linda: %.*s", (int) sizeof(text) - 8, linda->getName()); 668 _len = sprintf(_text, "Linda: %.*s", (int) sizeof(_text) - 8, _linda->getName());
669 else 669 else
670 len = sprintf(text, "Linda: %p", linda); 670 _len = sprintf(_text, "Linda: %p", _linda);
671 lua_pushlstring(L_, text, len); 671 lua_pushlstring(L_, _text, _len);
672 return 1; 672 return 1;
673 } 673 }
674 return 0; 674 return 0;
@@ -692,17 +692,17 @@ LUAG_FUNC(linda_tostring)
692 */ 692 */
693LUAG_FUNC(linda_concat) 693LUAG_FUNC(linda_concat)
694{ // L_: linda1? linda2? 694{ // L_: linda1? linda2?
695 bool atLeastOneLinda{ false }; 695 bool _atLeastOneLinda{ false };
696 // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both. 696 // Lua semantics enforce that one of the 2 arguments is a Linda, but not necessarily both.
697 if (LindaToString<true>(L_, 1)) { 697 if (LindaToString<true>(L_, 1)) {
698 atLeastOneLinda = true; 698 _atLeastOneLinda = true;
699 lua_replace(L_, 1); 699 lua_replace(L_, 1);
700 } 700 }
701 if (LindaToString<true>(L_, 2)) { 701 if (LindaToString<true>(L_, 2)) {
702 atLeastOneLinda = true; 702 _atLeastOneLinda = true;
703 lua_replace(L_, 2); 703 lua_replace(L_, 2);
704 } 704 }
705 if (!atLeastOneLinda) { // should not be possible 705 if (!_atLeastOneLinda) { // should not be possible
706 raise_luaL_error(L_, "internal error: linda_concat called on non-Linda"); 706 raise_luaL_error(L_, "internal error: linda_concat called on non-Linda");
707 } 707 }
708 lua_concat(L_, 2); 708 lua_concat(L_, 2);
@@ -717,11 +717,11 @@ LUAG_FUNC(linda_concat)
717 */ 717 */
718LUAG_FUNC(linda_dump) 718LUAG_FUNC(linda_dump)
719{ 719{
720 auto dump = [](lua_State* L_) { 720 auto _dump = [](lua_State* L_) {
721 Linda* const linda{ ToLinda<false>(L_, 1) }; 721 Linda* const _linda{ ToLinda<false>(L_, 1) };
722 return keeper_push_linda_storage(*linda, DestState{ L_ }); 722 return keeper_push_linda_storage(*_linda, DestState{ L_ });
723 }; 723 };
724 return Linda::ProtectedCall(L_, dump); 724 return Linda::ProtectedCall(L_, _dump);
725} 725}
726 726
727// ################################################################################################# 727// #################################################################################################
@@ -732,13 +732,13 @@ LUAG_FUNC(linda_dump)
732 */ 732 */
733LUAG_FUNC(linda_towatch) 733LUAG_FUNC(linda_towatch)
734{ 734{
735 Linda* const linda{ ToLinda<false>(L_, 1) }; 735 Linda* const _linda{ ToLinda<false>(L_, 1) };
736 int pushed{ keeper_push_linda_storage(*linda, DestState{ L_ }) }; 736 int _pushed{ keeper_push_linda_storage(*_linda, DestState{ L_ }) };
737 if (pushed == 0) { 737 if (_pushed == 0) {
738 // if the linda is empty, don't return nil 738 // if the linda is empty, don't return nil
739 pushed = LindaToString<false>(L_, 1); 739 _pushed = LindaToString<false>(L_, 1);
740 } 740 }
741 return pushed; 741 return _pushed;
742} 742}
743 743
744// ################################################################################################# 744// #################################################################################################
@@ -773,12 +773,12 @@ namespace global {
773 */ 773 */
774LUAG_FUNC(linda) 774LUAG_FUNC(linda)
775{ 775{
776 int const top{ lua_gettop(L_) }; 776 int const _top{ lua_gettop(L_) };
777 luaL_argcheck(L_, top <= 2, top, "too many arguments"); 777 luaL_argcheck(L_, _top <= 2, _top, "too many arguments");
778 if (top == 1) { 778 if (_top == 1) {
779 LuaType const t{ lua_type_as_enum(L_, 1) }; 779 LuaType const _t{ lua_type_as_enum(L_, 1) };
780 luaL_argcheck(L_, t == LuaType::STRING || t == LuaType::NUMBER, 1, "wrong parameter (should be a string or a number)"); 780 luaL_argcheck(L_, _t == LuaType::STRING || _t == LuaType::NUMBER, 1, "wrong parameter (should be a string or a number)");
781 } else if (top == 2) { 781 } else if (_top == 2) {
782 luaL_checktype(L_, 1, LUA_TSTRING); 782 luaL_checktype(L_, 1, LUA_TSTRING);
783 luaL_checktype(L_, 2, LUA_TNUMBER); 783 luaL_checktype(L_, 2, LUA_TNUMBER);
784 } 784 }