aboutsummaryrefslogtreecommitdiff
path: root/src/keeper.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/keeper.cpp655
1 files changed, 289 insertions, 366 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp
index cbdd0c9..5350d26 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -56,7 +56,6 @@
56class keeper_fifo 56class keeper_fifo
57{ 57{
58 public: 58 public:
59
60 int first{ 1 }; 59 int first{ 1 };
61 int count{ 0 }; 60 int count{ 0 };
62 int limit{ -1 }; 61 int limit{ -1 };
@@ -81,8 +80,7 @@ static constexpr int kContentsTableIndex{ 1 };
81[[nodiscard]] static keeper_fifo* prepare_fifo_access(lua_State* L_, int idx_) 80[[nodiscard]] static keeper_fifo* prepare_fifo_access(lua_State* L_, int idx_)
82{ 81{
83 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, idx_) }; 82 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, idx_) };
84 if (fifo != nullptr) 83 if (fifo != nullptr) {
85 {
86 idx_ = lua_absindex(L_, idx_); 84 idx_ = lua_absindex(L_, idx_);
87 STACK_GROW(L_, 1); 85 STACK_GROW(L_, 1);
88 // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around 86 // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around
@@ -117,8 +115,7 @@ static void fifo_push(lua_State* L_, keeper_fifo* fifo_, int count_)
117 int const idx{ lua_gettop(L_) - count_ }; 115 int const idx{ lua_gettop(L_) - count_ };
118 int const start{ fifo_->first + fifo_->count - 1 }; 116 int const start{ fifo_->first + fifo_->count - 1 };
119 // pop all additional arguments, storing them in the fifo 117 // pop all additional arguments, storing them in the fifo
120 for (int i = count_; i >= 1; --i) 118 for (int i = count_; i >= 1; --i) {
121 {
122 // store in the fifo the value at the top of the stack at the specified index, popping it from the stack 119 // store in the fifo the value at the top of the stack at the specified index, popping it from the stack
123 lua_rawseti(L_, idx, start + i); 120 lua_rawseti(L_, idx, start + i);
124 } 121 }
@@ -135,8 +132,7 @@ static void fifo_push(lua_State* L_, keeper_fifo* fifo_, int count_)
135static void fifo_peek(lua_State* L_, keeper_fifo* fifo_, int count_) 132static void fifo_peek(lua_State* L_, keeper_fifo* fifo_, int count_)
136{ 133{
137 STACK_GROW(L_, count_); 134 STACK_GROW(L_, count_);
138 for (int i = 0; i < count_; ++i) 135 for (int i = 0; i < count_; ++i) {
139 {
140 lua_rawgeti(L_, 1, (fifo_->first + i)); 136 lua_rawgeti(L_, 1, (fifo_->first + i));
141 } 137 }
142} 138}
@@ -145,29 +141,28 @@ static void fifo_peek(lua_State* L_, keeper_fifo* fifo_, int count_)
145 141
146// in: fifo 142// in: fifo
147// out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) 143// out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number)
148static void fifo_pop( lua_State* L_, keeper_fifo* fifo_, int count_) 144static void fifo_pop(lua_State* L_, keeper_fifo* fifo_, int count_)
149{ 145{
150 LUA_ASSERT(L_, lua_istable(L_, -1)); 146 LUA_ASSERT(L_, lua_istable(L_, -1));
151 int const fifo_idx{ lua_gettop(L_) }; // ... fifotbl 147 int const fifo_idx{ lua_gettop(L_) }; // L_: ... fifotbl
152 // each iteration pushes a value on the stack! 148 // each iteration pushes a value on the stack!
153 STACK_GROW(L_, count_ + 2); 149 STACK_GROW(L_, count_ + 2);
154 // skip first item, we will push it last 150 // skip first item, we will push it last
155 for (int i = 1; i < count_; ++i) 151 for (int i = 1; i < count_; ++i) {
156 {
157 int const at{ fifo_->first + i }; 152 int const at{ fifo_->first + i };
158 // push item on the stack 153 // push item on the stack
159 lua_rawgeti(L_, fifo_idx, at); // ... fifotbl val 154 lua_rawgeti(L_, fifo_idx, at); // L_: ... fifotbl val
160 // remove item from the fifo 155 // remove item from the fifo
161 lua_pushnil(L_); // ... fifotbl val nil 156 lua_pushnil(L_); // L_: ... fifotbl val nil
162 lua_rawseti(L_, fifo_idx, at); // ... fifotbl val 157 lua_rawseti(L_, fifo_idx, at); // L_: ... fifotbl val
163 } 158 }
164 // now process first item 159 // now process first item
165 { 160 {
166 int const at{ fifo_->first }; 161 int const at{ fifo_->first };
167 lua_rawgeti(L_, fifo_idx, at); // ... fifotbl vals val 162 lua_rawgeti(L_, fifo_idx, at); // L_: ... fifotbl vals val
168 lua_pushnil(L_); // ... fifotbl vals val nil 163 lua_pushnil(L_); // L_: ... fifotbl vals val nil
169 lua_rawseti(L_, fifo_idx, at); // ... fifotbl vals val 164 lua_rawseti(L_, fifo_idx, at); // L_: ... fifotbl vals val
170 lua_replace(L_, fifo_idx); // ... vals 165 lua_replace(L_, fifo_idx); // L_: ... vals
171 } 166 }
172 167
173 // avoid ever-growing indexes by resetting each time we detect the fifo is empty 168 // avoid ever-growing indexes by resetting each time we detect the fifo is empty
@@ -189,20 +184,19 @@ static void push_table(lua_State* L_, int idx_)
189 STACK_GROW(L_, 5); 184 STACK_GROW(L_, 5);
190 STACK_CHECK_START_REL(L_, 0); 185 STACK_CHECK_START_REL(L_, 0);
191 idx_ = lua_absindex(L_, idx_); 186 idx_ = lua_absindex(L_, idx_);
192 kFifosRegKey.pushValue(L_); // ud fifos 187 kFifosRegKey.pushValue(L_); // L_: ud fifos
193 lua_pushvalue(L_, idx_); // ud fifos ud 188 lua_pushvalue(L_, idx_); // L_: ud fifos ud
194 lua_rawget(L_, -2); // ud fifos fifos[ud] 189 lua_rawget(L_, -2); // L_: ud fifos fifos[ud]
195 STACK_CHECK(L_, 2); 190 STACK_CHECK(L_, 2);
196 if (lua_isnil(L_, -1)) 191 if (lua_isnil(L_, -1)) {
197 { 192 lua_pop(L_, 1); // L_: ud fifos
198 lua_pop(L_, 1); // ud fifos
199 // add a new fifos table for this linda 193 // add a new fifos table for this linda
200 lua_newtable(L_); // ud fifos fifos[ud] 194 lua_newtable(L_); // L_: ud fifos fifos[ud]
201 lua_pushvalue(L_, idx_); // ud fifos fifos[ud] ud 195 lua_pushvalue(L_, idx_); // L_: ud fifos fifos[ud] ud
202 lua_pushvalue(L_, -2); // ud fifos fifos[ud] ud fifos[ud] 196 lua_pushvalue(L_, -2); // L_: ud fifos fifos[ud] ud fifos[ud]
203 lua_rawset(L_, -4); // ud fifos fifos[ud] 197 lua_rawset(L_, -4); // L_: ud fifos fifos[ud]
204 } 198 }
205 lua_remove(L_, -2); // ud fifos[ud] 199 lua_remove(L_, -2); // L_: ud fifos[ud]
206 STACK_CHECK(L_, 1); 200 STACK_CHECK(L_, 1);
207} 201}
208 202
@@ -215,47 +209,45 @@ int keeper_push_linda_storage(Linda& linda_, DestState L_)
215 SourceState const KL{ K ? K->L : nullptr }; 209 SourceState const KL{ K ? K->L : nullptr };
216 if (KL == nullptr) 210 if (KL == nullptr)
217 return 0; 211 return 0;
218 STACK_GROW(KL, 4); // KEEPER MAIN 212 STACK_GROW(KL, 4);
219 STACK_CHECK_START_REL(KL, 0); 213 STACK_CHECK_START_REL(KL, 0);
220 kFifosRegKey.pushValue(KL); // fifos 214 kFifosRegKey.pushValue(KL); // KL: fifos L_:
221 lua_pushlightuserdata(KL, &linda_); // fifos ud 215 lua_pushlightuserdata(KL, &linda_); // KL: fifos ud L_:
222 lua_rawget(KL, -2); // fifos storage 216 lua_rawget(KL, -2); // KL: fifos storage L_:
223 lua_remove(KL, -2); // storage 217 lua_remove(KL, -2); // KL: storage L_:
224 if (!lua_istable(KL, -1)) 218 if (!lua_istable(KL, -1)) {
225 { 219 lua_pop(KL, 1); // KL: L_:
226 lua_pop(KL, 1); //
227 STACK_CHECK(KL, 0); 220 STACK_CHECK(KL, 0);
228 return 0; 221 return 0;
229 } 222 }
230 // move data from keeper to destination state 223 // move data from keeper to destination state
231 STACK_GROW(L_, 5); 224 STACK_GROW(L_, 5);
232 STACK_CHECK_START_REL(L_, 0); 225 STACK_CHECK_START_REL(L_, 0);
233 lua_newtable(L_); // out 226 lua_newtable(L_); // KL: storage L_: out
234 InterCopyContext c{ linda_.U, L_, KL, {}, {}, {}, LookupMode::FromKeeper, {} }; 227 InterCopyContext c{ linda_.U, L_, KL, {}, {}, {}, LookupMode::FromKeeper, {} };
235 lua_pushnil(KL); // storage nil 228 lua_pushnil(KL); // KL: storage nil L_: out
236 while (lua_next(KL, -2)) // storage key fifo 229 while (lua_next(KL, -2)) { // KL: storage key fifo L_: out
237 { 230 keeper_fifo* fifo = prepare_fifo_access(KL, -1); // KL: storage key fifotbl L_: out
238 keeper_fifo* fifo = prepare_fifo_access(KL, -1); // storage key fifotbl 231 lua_pushvalue(KL, -2); // KL: storage key fifotbl key L_: out
239 lua_pushvalue(KL, -2); // storage key fifotbl key 232 std::ignore = c.inter_move(1); // KL: storage key fifotbl L_: out key
240 std::ignore = c.inter_move(1); // storage key fifotbl // out key
241 STACK_CHECK(L_, 2); 233 STACK_CHECK(L_, 2);
242 lua_newtable(L_); // out key keyout 234 lua_newtable(L_); // KL: storage key L_: out key keyout
243 std::ignore = c.inter_move(1); // storage key // out key keyout fifotbl 235 std::ignore = c.inter_move(1); // KL: storage key L_: out key keyout fifotbl
244 lua_pushinteger(L_, fifo->first); // out key keyout fifotbl first 236 lua_pushinteger(L_, fifo->first); // KL: storage key L_: out key keyout fifotbl first
245 STACK_CHECK(L_, 5); 237 STACK_CHECK(L_, 5);
246 lua_setfield(L_, -3, "first"); // out key keyout fifotbl 238 lua_setfield(L_, -3, "first"); // KL: storage key L_: out key keyout fifotbl
247 lua_pushinteger(L_, fifo->count); // out key keyout fifobtl count 239 lua_pushinteger(L_, fifo->count); // KL: storage key L_: out key keyout fifobtl count
248 STACK_CHECK(L_, 5); 240 STACK_CHECK(L_, 5);
249 lua_setfield(L_, -3, "count"); // out key keyout fifotbl 241 lua_setfield(L_, -3, "count"); // KL: storage key L_: out key keyout fifotbl
250 lua_pushinteger(L_, fifo->limit); // out key keyout fifotbl limit 242 lua_pushinteger(L_, fifo->limit); // KL: storage key L_: out key keyout fifotbl limit
251 STACK_CHECK(L_, 5); 243 STACK_CHECK(L_, 5);
252 lua_setfield(L_, -3, "limit"); // out key keyout fifotbl 244 lua_setfield(L_, -3, "limit"); // KL: storage key L_: out key keyout fifotbl
253 lua_setfield(L_, -2, "fifo"); // out key keyout 245 lua_setfield(L_, -2, "fifo"); // KL: storage key L_: out key keyout
254 lua_rawset(L_, -3); // out 246 lua_rawset(L_, -3); // KL: storage key L_: out
255 STACK_CHECK(L_, 1); 247 STACK_CHECK(L_, 1);
256 } 248 } // KL_: storage L_: out
257 STACK_CHECK(L_, 1); 249 STACK_CHECK(L_, 1);
258 lua_pop(KL, 1); // 250 lua_pop(KL, 1); // KL: L_: out
259 STACK_CHECK(KL, 0); 251 STACK_CHECK(KL, 0);
260 return 1; 252 return 1;
261} 253}
@@ -267,11 +259,11 @@ int keepercall_clear(lua_State* L_)
267{ 259{
268 STACK_GROW(L_, 3); 260 STACK_GROW(L_, 3);
269 STACK_CHECK_START_REL(L_, 0); 261 STACK_CHECK_START_REL(L_, 0);
270 kFifosRegKey.pushValue(L_); // ud fifos 262 kFifosRegKey.pushValue(L_); // L_: ud fifos
271 lua_pushvalue(L_, 1); // ud fifos ud 263 lua_pushvalue(L_, 1); // L_: ud fifos ud
272 lua_pushnil(L_); // ud fifos ud nil 264 lua_pushnil(L_); // L_: ud fifos ud nil
273 lua_rawset(L_, -3); // ud fifos 265 lua_rawset(L_, -3); // L_: ud fifos
274 lua_pop(L_, 1); // ud 266 lua_pop(L_, 1); // L_: ud
275 STACK_CHECK(L_, 0); 267 STACK_CHECK(L_, 0);
276 return 0; 268 return 0;
277} 269}
@@ -283,32 +275,28 @@ int keepercall_clear(lua_State* L_)
283int keepercall_send(lua_State* L_) 275int keepercall_send(lua_State* L_)
284{ 276{
285 int const n{ lua_gettop(L_) - 2 }; 277 int const n{ lua_gettop(L_) - 2 };
286 push_table(L_, 1); // ud key ... fifos 278 push_table(L_, 1); // L_: ud key ... fifos
287 // get the fifo associated to this key in this linda, create it if it doesn't exist 279 // get the fifo associated to this key in this linda, create it if it doesn't exist
288 lua_pushvalue(L_, 2); // ud key ... fifos key 280 lua_pushvalue(L_, 2); // L_: ud key ... fifos key
289 lua_rawget(L_, -2); // ud key ... fifos fifo 281 lua_rawget(L_, -2); // L_: ud key ... fifos fifo
290 if (lua_isnil(L_, -1)) 282 if (lua_isnil(L_, -1)) {
291 { 283 lua_pop(L_, 1); // L_: ud key ... fifos
292 lua_pop(L_, 1); // ud key ... fifos 284 std::ignore = fifo_new(KeeperState{ L_ }); // L_: ud key ... fifos fifo
293 std::ignore = fifo_new(KeeperState{ L_ }); // ud key ... fifos fifo 285 lua_pushvalue(L_, 2); // L_: ud key ... fifos fifo key
294 lua_pushvalue(L_, 2); // ud key ... fifos fifo key 286 lua_pushvalue(L_, -2); // L_: ud key ... fifos fifo key fifo
295 lua_pushvalue(L_, -2); // ud key ... fifos fifo key fifo 287 lua_rawset(L_, -4); // L_: ud key ... fifos fifo
296 lua_rawset(L_, -4); // ud key ... fifos fifo 288 }
297 } 289 lua_remove(L_, -2); // L_: ud key ... fifo
298 lua_remove(L_, -2); // ud key ... fifo
299 keeper_fifo* fifo{ keeper_fifo::getPtr(L_, -1) }; 290 keeper_fifo* fifo{ keeper_fifo::getPtr(L_, -1) };
300 if (fifo->limit >= 0 && fifo->count + n > fifo->limit) 291 if (fifo->limit >= 0 && fifo->count + n > fifo->limit) {
301 { 292 lua_settop(L_, 0); // L_:
302 lua_settop(L_, 0); // 293 lua_pushboolean(L_, 0); // L_:false
303 lua_pushboolean(L_, 0); // false 294 } else {
304 } 295 fifo = prepare_fifo_access(L_, -1); // L_: ud fifotbl
305 else 296 lua_replace(L_, 2); // L_: ud fifotbl ...
306 { 297 fifo_push(L_, fifo, n); // L_: ud fifotbl
307 fifo = prepare_fifo_access(L_, -1); // ud fifotbl 298 lua_settop(L_, 0); // L_:
308 lua_replace(L_, 2); // ud fifotbl ... 299 lua_pushboolean(L_, 1); // L_: true
309 fifo_push(L_, fifo, n); // ud fifotbl
310 lua_settop(L_, 0); //
311 lua_pushboolean(L_, 1); // true
312 } 300 }
313 return 1; 301 return 1;
314} 302}
@@ -320,30 +308,26 @@ int keepercall_send(lua_State* L_)
320int keepercall_receive(lua_State* L_) 308int keepercall_receive(lua_State* L_)
321{ 309{
322 int const top{ lua_gettop(L_) }; 310 int const top{ lua_gettop(L_) };
323 push_table(L_, 1); // ud keys fifos 311 push_table(L_, 1); // L_: ud keys fifos
324 lua_replace(L_, 1); // fifos keys 312 lua_replace(L_, 1); // L_: fifos keys
325 for (int i = 2; i <= top; ++i) 313 for (int i = 2; i <= top; ++i) {
326 { 314 lua_pushvalue(L_, i); // L_: fifos keys key[i]
327 lua_pushvalue(L_, i); // fifos keys key[i] 315 lua_rawget(L_, 1); // L_: fifos keys fifo
328 lua_rawget(L_, 1); // fifos keys fifo 316 keeper_fifo* const fifo{ prepare_fifo_access(L_, -1) }; // L_: fifos keys fifotbl
329 keeper_fifo* const fifo{ prepare_fifo_access(L_, -1) }; // fifos keys fifotbl 317 if (fifo != nullptr && fifo->count > 0) {
330 if (fifo != nullptr && fifo->count > 0) 318 fifo_pop(L_, fifo, 1); // L_: fifos keys val
331 { 319 if (!lua_isnil(L_, -1)) {
332 fifo_pop(L_, fifo, 1); // fifos keys val 320 lua_replace(L_, 1); // L_: val keys
333 if (!lua_isnil(L_, -1)) 321 lua_settop(L_, i); // L_: val keys key[i]
334 { 322 if (i != 2) {
335 lua_replace(L_, 1); // val keys 323 lua_replace(L_, 2); // L_: val key keys
336 lua_settop(L_, i); // val keys key[i] 324 lua_settop(L_, 2); // L_: val key
337 if (i != 2)
338 {
339 lua_replace(L_, 2); // val key keys
340 lua_settop(L_, 2); // val key
341 } 325 }
342 lua_insert(L_, 1); // key, val 326 lua_insert(L_, 1); // L_: key, val
343 return 2; 327 return 2;
344 } 328 }
345 } 329 }
346 lua_settop(L_, top); // data keys 330 lua_settop(L_, top); // L_: data keys
347 } 331 }
348 // nothing to receive 332 // nothing to receive
349 return 0; 333 return 0;
@@ -355,29 +339,23 @@ int keepercall_receive(lua_State* L_)
355int keepercall_receive_batched(lua_State* L_) 339int keepercall_receive_batched(lua_State* L_)
356{ 340{
357 int const min_count{ static_cast<int>(lua_tointeger(L_, 3)) }; 341 int const min_count{ static_cast<int>(lua_tointeger(L_, 3)) };
358 if (min_count > 0) 342 if (min_count > 0) {
359 {
360 int const max_count{ static_cast<int>(luaL_optinteger(L_, 4, min_count)) }; 343 int const max_count{ static_cast<int>(luaL_optinteger(L_, 4, min_count)) };
361 lua_settop(L_, 2); // ud key 344 lua_settop(L_, 2); // L_: ud key
362 lua_insert(L_, 1); // key ud 345 lua_insert(L_, 1); // L_: key ud
363 push_table(L_, 2); // key ud fifos 346 push_table(L_, 2); // L_: key ud fifos
364 lua_remove(L_, 2); // key fifos 347 lua_remove(L_, 2); // L_: key fifos
365 lua_pushvalue(L_, 1); // key fifos key 348 lua_pushvalue(L_, 1); // L_: key fifos key
366 lua_rawget(L_, 2); // key fifos fifo 349 lua_rawget(L_, 2); // L_: key fifos fifo
367 lua_remove(L_, 2); // key fifo 350 lua_remove(L_, 2); // L_: key fifo
368 keeper_fifo* const fifo{ prepare_fifo_access(L_, 2) }; // key fifotbl 351 keeper_fifo* const fifo{ prepare_fifo_access(L_, 2) }; // L_: key fifotbl
369 if (fifo != nullptr && fifo->count >= min_count) 352 if (fifo != nullptr && fifo->count >= min_count) {
370 { 353 fifo_pop(L_, fifo, std::min(max_count, fifo->count)); // L_: key ...
371 fifo_pop(L_, fifo, std::min( max_count, fifo->count)); // key ... 354 } else {
372 } 355 lua_settop(L_, 0); // L_:
373 else
374 {
375 lua_settop(L_, 0); //
376 } 356 }
377 return lua_gettop(L_); 357 return lua_gettop(L_);
378 } 358 } else {
379 else
380 {
381 return 0; 359 return 0;
382 } 360 }
383} 361}
@@ -389,28 +367,26 @@ int keepercall_receive_batched(lua_State* L_)
389int keepercall_limit(lua_State* L_) 367int keepercall_limit(lua_State* L_)
390{ 368{
391 int const limit{ static_cast<int>(lua_tointeger(L_, 3)) }; 369 int const limit{ static_cast<int>(lua_tointeger(L_, 3)) };
392 push_table(L_, 1); // ud key n fifos 370 push_table(L_, 1); // L_: ud key n fifos
393 lua_replace(L_, 1); // fifos key n 371 lua_replace(L_, 1); // L_: fifos key n
394 lua_pop(L_, 1); // fifos key 372 lua_pop(L_, 1); // L_: fifos key
395 lua_pushvalue(L_, -1); // fifos key key 373 lua_pushvalue(L_, -1); // L_: fifos key key
396 lua_rawget(L_, -3); // fifos key fifo|nil 374 lua_rawget(L_, -3); // L_: fifos key fifo|nil
397 keeper_fifo* fifo{ keeper_fifo::getPtr(L_, -1) }; 375 keeper_fifo* fifo{ keeper_fifo::getPtr(L_, -1) };
398 if (fifo == nullptr) 376 if (fifo == nullptr) { // L_: fifos key nil
399 { // fifos key nil 377 lua_pop(L_, 1); // L_: fifos key
400 lua_pop(L_, 1); // fifos key 378 fifo = fifo_new(KeeperState{ L_ }); // L_: fifos key fifo
401 fifo = fifo_new(KeeperState{ L_ }); // fifos key fifo 379 lua_rawset(L_, -3); // L_: fifos
402 lua_rawset(L_, -3); // fifos
403 } 380 }
404 // remove any clutter on the stack 381 // remove any clutter on the stack
405 lua_settop(L_, 0); 382 lua_settop(L_, 0); // L_:
406 // return true if we decide that blocked threads waiting to write on that key should be awakened 383 // return true if we decide that blocked threads waiting to write on that key should be awakened
407 // this is the case if we detect the key was full but it is no longer the case 384 // this is the case if we detect the key was full but it is no longer the case
408 if ( 385 if (
409 ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit 386 ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit
410 && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit 387 && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit
411 ) 388 ) {
412 { 389 lua_pushboolean(L_, 1); // L_: true
413 lua_pushboolean(L_, 1); // true
414 } 390 }
415 // set the new limit 391 // set the new limit
416 fifo->limit = limit; 392 fifo->limit = limit;
@@ -421,72 +397,63 @@ int keepercall_limit(lua_State* L_)
421// ################################################################################################# 397// #################################################################################################
422 398
423// in: linda_ud key [[val] ...] 399// in: linda_ud key [[val] ...]
424//out: true if the linda was full but it's no longer the case, else nothing 400// out: true if the linda was full but it's no longer the case, else nothing
425int keepercall_set(lua_State* L_) 401int keepercall_set(lua_State* L_)
426{ 402{
427 bool should_wake_writers{ false }; 403 bool should_wake_writers{ false };
428 STACK_GROW(L_, 6); 404 STACK_GROW(L_, 6);
429 405
430 // retrieve fifos associated with the linda 406 // retrieve fifos associated with the linda
431 push_table(L_, 1); // ud key [val [, ...]] fifos 407 push_table(L_, 1); // L_: ud key [val [, ...]] fifos
432 lua_replace(L_, 1); // fifos key [val [, ...]] 408 lua_replace(L_, 1); // L_: fifos key [val [, ...]]
433 409
434 // make sure we have a value on the stack 410 // make sure we have a value on the stack
435 if (lua_gettop(L_) == 2) // fifos key 411 if (lua_gettop(L_) == 2) { // L_: fifos key
436 { 412 lua_pushvalue(L_, -1); // L_: fifos key key
437 lua_pushvalue(L_, -1); // fifos key key 413 lua_rawget(L_, 1); // L_: fifos key fifo|nil
438 lua_rawget(L_, 1); // fifos key fifo|nil
439 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 414 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
440 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) }; 415 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) };
441 if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil 416 if (fifo != nullptr) { // might be nullptr if we set a nonexistent key to nil // L_: fifos key fifo
442 { // fifos key fifo 417 if (fifo->limit < 0) { // fifo limit value is the default (unlimited): we can totally remove it
443 if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it 418 lua_pop(L_, 1); // L_: fifos key
444 { 419 lua_pushnil(L_); // L_: fifos key nil
445 lua_pop(L_, 1); // fifos key 420 lua_rawset(L_, -3); // L_: fifos
446 lua_pushnil(L_); // fifos key nil 421 } else {
447 lua_rawset(L_, -3); // fifos
448 }
449 else
450 {
451 // we create room if the fifo was full but it is no longer the case 422 // we create room if the fifo was full but it is no longer the case
452 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); 423 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit);
453 lua_remove(L_, -2); // fifos fifo 424 lua_remove(L_, -2); // L_: fifos fifo
454 lua_newtable(L_); // fifos fifo {} 425 lua_newtable(L_); // L_: fifos fifo {}
455 lua_setiuservalue(L_, -2, kContentsTableIndex); // fifos fifo 426 lua_setiuservalue(L_, -2, kContentsTableIndex); // L_: fifos fifo
456 fifo->first = 1; 427 fifo->first = 1;
457 fifo->count = 0; 428 fifo->count = 0;
458 } 429 }
459 } 430 }
460 } 431 } else { // set/replace contents stored at the specified key?
461 else // set/replace contents stored at the specified key? 432 int const count{ lua_gettop(L_) - 2 }; // number of items we want to store
462 { 433 lua_pushvalue(L_, 2); // L_: fifos key [val [, ...]] key
463 int const count{ lua_gettop(L_) - 2 }; // number of items we want to store 434 lua_rawget(L_, 1); // L_: fifos key [val [, ...]] fifo|nil
464 lua_pushvalue(L_, 2); // fifos key [val [, ...]] key
465 lua_rawget(L_, 1); // fifos key [val [, ...]] fifo|nil
466 keeper_fifo* fifo{ keeper_fifo::getPtr(L_, -1) }; 435 keeper_fifo* fifo{ keeper_fifo::getPtr(L_, -1) };
467 if (fifo == nullptr) // can be nullptr if we store a value at a new key 436 if (fifo == nullptr) { // can be nullptr if we store a value at a new key // fifos key [val [, ...]] nil
468 { // fifos key [val [, ...]] nil
469 // no need to wake writers in that case, because a writer can't wait on an inexistent key 437 // no need to wake writers in that case, because a writer can't wait on an inexistent key
470 lua_pop(L_, 1); // fifos key [val [, ...]] 438 lua_pop(L_, 1); // L_: fifos key [val [, ...]]
471 std::ignore = fifo_new(KeeperState{ L_ }); // fifos key [val [, ...]] fifo 439 std::ignore = fifo_new(KeeperState{ L_ }); // L_: fifos key [val [, ...]] fifo
472 lua_pushvalue(L_, 2); // fifos key [val [, ...]] fifo key 440 lua_pushvalue(L_, 2); // L_: fifos key [val [, ...]] fifo key
473 lua_pushvalue(L_, -2); // fifos key [val [, ...]] fifo key fifo 441 lua_pushvalue(L_, -2); // L_: fifos key [val [, ...]] fifo key fifo
474 lua_rawset(L_, 1); // fifos key [val [, ...]] fifo 442 lua_rawset(L_, 1); // L_: fifos key [val [, ...]] fifo
475 } 443 } else { // L_: fifos key [val [, ...]] fifo
476 else // the fifo exists, we just want to update its contents 444 // the fifo exists, we just want to update its contents
477 { // fifos key [val [, ...]] fifo
478 // we create room if the fifo was full but it is no longer the case 445 // we create room if the fifo was full but it is no longer the case
479 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit); 446 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit);
480 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 447 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
481 lua_newtable(L_); // fifos key [val [, ...]] fifo {} 448 lua_newtable(L_); // L_: fifos key [val [, ...]] fifo {}
482 lua_setiuservalue(L_, -2, kContentsTableIndex); // fifos key [val [, ...]] fifo 449 lua_setiuservalue(L_, -2, kContentsTableIndex); // L_: fifos key [val [, ...]] fifo
483 fifo->first = 1; 450 fifo->first = 1;
484 fifo->count = 0; 451 fifo->count = 0;
485 } 452 }
486 fifo = prepare_fifo_access(L_, -1); // fifos key [val [, ...]] fifotbl 453 fifo = prepare_fifo_access(L_, -1); // L_: fifos key [val [, ...]] fifotbl
487 // move the fifo below the values we want to store 454 // move the fifo below the values we want to store
488 lua_insert(L_, 3); // fifos key fifotbl [val [, ...]] 455 lua_insert(L_, 3); // L_: fifos key fifotbl [val [, ...]]
489 fifo_push(L_, fifo, count); // fifos key fifotbl 456 fifo_push(L_, fifo, count); // L_: fifos key fifotbl
490 } 457 }
491 return should_wake_writers ? (lua_pushboolean(L_, 1), 1) : 0; 458 return should_wake_writers ? (lua_pushboolean(L_, 1), 1) : 0;
492} 459}
@@ -498,21 +465,19 @@ int keepercall_set(lua_State* L_)
498int keepercall_get(lua_State* L_) 465int keepercall_get(lua_State* L_)
499{ 466{
500 int count{ 1 }; 467 int count{ 1 };
501 if (lua_gettop(L_) == 3) // ud key count 468 if (lua_gettop(L_) == 3) { // L_: ud key count
502 {
503 count = static_cast<int>(lua_tointeger(L_, 3)); 469 count = static_cast<int>(lua_tointeger(L_, 3));
504 lua_pop(L_, 1); // ud key 470 lua_pop(L_, 1); // L_: ud key
505 } 471 }
506 push_table(L_, 1); // ud key fifos 472 push_table(L_, 1); // L_: ud key fifos
507 lua_replace(L_, 1); // fifos key 473 lua_replace(L_, 1); // L_: fifos key
508 lua_rawget(L_, 1); // fifos fifo 474 lua_rawget(L_, 1); // L_: fifos fifo
509 keeper_fifo* const fifo{ prepare_fifo_access(L_, -1) }; // fifos fifotbl 475 keeper_fifo* const fifo{ prepare_fifo_access(L_, -1) }; // L_: fifos fifotbl
510 if (fifo != nullptr && fifo->count > 0) 476 if (fifo != nullptr && fifo->count > 0) {
511 { 477 lua_remove(L_, 1); // L_: fifotbl
512 lua_remove(L_, 1); // fifotbl
513 count = std::min(count, fifo->count); 478 count = std::min(count, fifo->count);
514 // read <count> value off the fifo 479 // read <count> value off the fifo
515 fifo_peek(L_, fifo, count); // fifotbl ... 480 fifo_peek(L_, fifo, count); // L_: fifotbl ...
516 return count; 481 return count;
517 } 482 }
518 // no fifo was ever registered for this key, or it is empty 483 // no fifo was ever registered for this key, or it is empty
@@ -524,65 +489,56 @@ int keepercall_get(lua_State* L_)
524// in: linda_ud [, key [, ...]] 489// in: linda_ud [, key [, ...]]
525int keepercall_count(lua_State* L_) 490int keepercall_count(lua_State* L_)
526{ 491{
527 push_table(L_, 1); // ud keys fifos 492 push_table(L_, 1); // L_: ud keys fifos
528 switch (lua_gettop(L_)) 493 switch (lua_gettop(L_)) {
529 { 494 // no key is specified: return a table giving the count of all known keys
530 // no key is specified: return a table giving the count of all known keys 495 case 2: // L_: ud fifos
531 case 2: // ud fifos 496 lua_newtable(L_); // L_: ud fifos out
532 lua_newtable(L_); // ud fifos out 497 lua_replace(L_, 1); // L_: out fifos
533 lua_replace(L_, 1); // out fifos 498 lua_pushnil(L_); // L_: out fifos nil
534 lua_pushnil(L_); // out fifos nil 499 while (lua_next(L_, 2)) { // L_: out fifos key fifo
535 while (lua_next(L_, 2)) // out fifos key fifo
536 {
537 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) }; 500 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) };
538 lua_pop(L_, 1); // out fifos key 501 lua_pop(L_, 1); // L_: out fifos key
539 lua_pushvalue(L_, -1); // out fifos key key 502 lua_pushvalue(L_, -1); // L_: out fifos key key
540 lua_pushinteger(L_, fifo->count); // out fifos key key count 503 lua_pushinteger(L_, fifo->count); // L_: out fifos key key count
541 lua_rawset(L_, -5); // out fifos key 504 lua_rawset(L_, -5); // L_: out fifos key
542 } 505 }
543 lua_pop(L_, 1); // out 506 lua_pop(L_, 1); // L_: out
544 break; 507 break;
545 508
546 // 1 key is specified: return its count 509 // 1 key is specified: return its count
547 case 3: // ud key fifos 510 case 3: // L_: ud key fifos
548 lua_replace(L_, 1); // fifos key 511 lua_replace(L_, 1); // L_: fifos key
549 lua_rawget(L_, -2); // fifos fifo|nil 512 lua_rawget(L_, -2); // L_: fifos fifo|nil
550 if (lua_isnil(L_, -1)) // the key is unknown 513 if (lua_isnil(L_, -1)) { // L_: the key is unknown // L_: fifos nil
551 { // fifos nil 514 lua_remove(L_, -2); // L_: nil
552 lua_remove(L_, -2); // nil 515 } else { // the key is known // L_: fifos fifo
553 }
554 else // the key is known
555 { // fifos fifo
556 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) }; 516 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) };
557 lua_pushinteger(L_, fifo->count); // fifos fifo count 517 lua_pushinteger(L_, fifo->count); // L_: fifos fifo count
558 lua_replace(L_, -3); // count fifo 518 lua_replace(L_, -3); // L_: count fifo
559 lua_pop(L_, 1); // count 519 lua_pop(L_, 1); // L_: count
560 } 520 }
561 break; 521 break;
562 522
563 // a variable number of keys is specified: return a table of their counts 523 // a variable number of keys is specified: return a table of their counts
564 default: // ud keys fifos 524 default: // ud keys fifos
565 lua_newtable(L_); // ud keys... fifos out 525 lua_newtable(L_); // L_: ud keys... fifos out
566 lua_replace(L_, 1); // out keys... fifos 526 lua_replace(L_, 1); // L_: out keys... fifos
567 // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable 527 // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable
568 lua_insert(L_, 2); // out fifos keys... 528 lua_insert(L_, 2); // L_: out fifos keys...
569 while (lua_gettop(L_) > 2) 529 while (lua_gettop(L_) > 2) {
570 { 530 lua_pushvalue(L_, -1); // L_: out fifos keys... key
571 lua_pushvalue(L_, -1); // out fifos keys... key 531 lua_rawget(L_, 2); // L_: out fifos keys... fifo|nil
572 lua_rawget(L_, 2); // out fifos keys... fifo|nil
573 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) }; 532 keeper_fifo* const fifo{ keeper_fifo::getPtr(L_, -1) };
574 lua_pop(L_, 1); // out fifos keys... 533 lua_pop(L_, 1); // L_: out fifos keys...
575 if (fifo != nullptr) // the key is known 534 if (fifo != nullptr) { // L_: the key is known
576 { 535 lua_pushinteger(L_, fifo->count); // L_: out fifos keys... count
577 lua_pushinteger(L_, fifo->count); // out fifos keys... count 536 lua_rawset(L_, 1); // L_: out fifos keys...
578 lua_rawset(L_, 1); // out fifos keys... 537 } else { // the key is unknown
538 lua_pop(L_, 1); // L_: out fifos keys...
579 } 539 }
580 else // the key is unknown 540 } // all keys are exhausted // L_: out fifos
581 { 541 lua_pop(L_, 1); // L_: out
582 lua_pop(L_, 1); // out fifos keys...
583 }
584 } // all keys are exhausted // out fifos
585 lua_pop(L_, 1); // out
586 } 542 }
587 LUA_ASSERT(L_, lua_gettop(L_) == 1); 543 LUA_ASSERT(L_, lua_gettop(L_) == 1);
588 return 1; 544 return 1;
@@ -592,49 +548,40 @@ int keepercall_count(lua_State* L_)
592// Keeper API, accessed from linda methods 548// Keeper API, accessed from linda methods
593// ################################################################################################# 549// #################################################################################################
594 550
595/*---=== Keeper states ===---
596*/
597
598/* 551/*
599* Pool of keeper states 552 * Pool of keeper states
600* 553 *
601* Access to keeper states is locked (only one OS thread at a time) so the 554 * Access to keeper states is locked (only one OS thread at a time) so the
602* bigger the pool, the less chances of unnecessary waits. Lindas map to the 555 * bigger the pool, the less chances of unnecessary waits. Lindas map to the
603* keepers randomly, by a hash. 556 * keepers randomly, by a hash.
604*/ 557 */
605 558
606// called as __gc for the keepers array userdata 559// called as __gc for the keepers array userdata
607void close_keepers(Universe* U) 560void close_keepers(Universe* U_)
608{ 561{
609 if (U->keepers != nullptr) 562 if (U_->keepers != nullptr) {
610 { 563 int nbKeepers{ U_->keepers->nb_keepers };
611 int nbKeepers = U->keepers->nb_keepers;
612 // NOTE: imagine some keeper state N+1 currently holds a linda that uses another keeper N, and a _gc that will make use of it 564 // NOTE: imagine some keeper state N+1 currently holds a linda that uses another keeper N, and a _gc that will make use of it
613 // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists 565 // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists
614 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success 566 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success
615 // which is early-outed with a U->keepers->nbKeepers null-check 567 // which is early-outed with a U->keepers->nbKeepers null-check
616 U->keepers->nb_keepers = 0; 568 U_->keepers->nb_keepers = 0;
617 for (int i = 0; i < nbKeepers; ++i) 569 for (int i = 0; i < nbKeepers; ++i) {
618 { 570 lua_State* const K{ U_->keepers->keeper_array[i].L };
619 lua_State* K = U->keepers->keeper_array[i].L; 571 U_->keepers->keeper_array[i].L = KeeperState{ nullptr };
620 U->keepers->keeper_array[i].L = KeeperState{ nullptr }; 572 if (K != nullptr) {
621 if (K != nullptr)
622 {
623 lua_close(K); 573 lua_close(K);
624 } 574 } else {
625 else
626 {
627 // detected partial init: destroy only the mutexes that got initialized properly 575 // detected partial init: destroy only the mutexes that got initialized properly
628 nbKeepers = i; 576 nbKeepers = i;
629 } 577 }
630 } 578 }
631 for (int i = 0; i < nbKeepers; ++i) 579 for (int i = 0; i < nbKeepers; ++i) {
632 { 580 U_->keepers->keeper_array[i].~Keeper();
633 U->keepers->keeper_array[i].~Keeper();
634 } 581 }
635 // free the keeper bookkeeping structure 582 // free the keeper bookkeeping structure
636 U->internal_allocator.free(U->keepers, sizeof(Keepers) + (nbKeepers - 1) * sizeof(Keeper)); 583 U_->internal_allocator.free(U_->keepers, sizeof(Keepers) + (nbKeepers - 1) * sizeof(Keeper));
637 U->keepers = nullptr; 584 U_->keepers = nullptr;
638 } 585 }
639} 586}
640 587
@@ -651,98 +598,90 @@ void close_keepers(Universe* U)
651 * function never fails. 598 * function never fails.
652 * settings table is expected at position 1 on the stack 599 * settings table is expected at position 1 on the stack
653 */ 600 */
654void init_keepers(Universe* U, lua_State* L_) 601void init_keepers(Universe* U_, lua_State* L_)
655{ 602{
656 LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1)); 603 LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1));
657 STACK_CHECK_START_REL(L_, 0); // L_ K 604 STACK_CHECK_START_REL(L_, 0); // L_: settings
658 lua_getfield(L_, 1, "nb_keepers"); // settings nb_keepers 605 lua_getfield(L_, 1, "nb_keepers"); // L_: settings nb_keepers
659 int const nb_keepers{ static_cast<int>(lua_tointeger(L_, -1)) }; 606 int const nb_keepers{ static_cast<int>(lua_tointeger(L_, -1)) };
660 lua_pop(L_, 1); // settings 607 lua_pop(L_, 1); // L_: settings
661 if (nb_keepers < 1) 608 if (nb_keepers < 1) {
662 {
663 raise_luaL_error(L_, "Bad number of keepers (%d)", nb_keepers); 609 raise_luaL_error(L_, "Bad number of keepers (%d)", nb_keepers);
664 } 610 }
665 STACK_CHECK(L_, 0); 611 STACK_CHECK(L_, 0);
666 612
667 lua_getfield(L_, 1, "keepers_gc_threshold"); // settings keepers_gc_threshold 613 lua_getfield(L_, 1, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold
668 int const keepers_gc_threshold{ static_cast<int>(lua_tointeger(L_, -1)) }; 614 int const keepers_gc_threshold{ static_cast<int>(lua_tointeger(L_, -1)) };
669 lua_pop(L_, 1); // settings 615 lua_pop(L_, 1); // L_: settings
670 STACK_CHECK(L_, 0); 616 STACK_CHECK(L_, 0);
671 617
672 // Keepers contains an array of 1 Keeper, adjust for the actual number of keeper states 618 // Keepers contains an array of 1 Keeper, adjust for the actual number of keeper states
673 { 619 {
674 size_t const bytes = sizeof(Keepers) + (nb_keepers - 1) * sizeof(Keeper); 620 size_t const bytes = sizeof(Keepers) + (nb_keepers - 1) * sizeof(Keeper);
675 U->keepers = static_cast<Keepers*>(U->internal_allocator.alloc(bytes)); 621 U_->keepers = static_cast<Keepers*>(U_->internal_allocator.alloc(bytes));
676 if (U->keepers == nullptr) 622 if (U_->keepers == nullptr) {
677 {
678 raise_luaL_error(L_, "init_keepers() failed while creating keeper array; out of memory"); 623 raise_luaL_error(L_, "init_keepers() failed while creating keeper array; out of memory");
679 } 624 }
680 U->keepers->Keepers::Keepers(); 625 U_->keepers->Keepers::Keepers();
681 U->keepers->gc_threshold = keepers_gc_threshold; 626 U_->keepers->gc_threshold = keepers_gc_threshold;
682 U->keepers->nb_keepers = nb_keepers; 627 U_->keepers->nb_keepers = nb_keepers;
683 628
684 for (int i = 0; i < nb_keepers; ++i) 629 for (int i = 0; i < nb_keepers; ++i) {
685 { 630 U_->keepers->keeper_array[i].Keeper::Keeper();
686 U->keepers->keeper_array[i].Keeper::Keeper();
687 } 631 }
688 } 632 }
689 for (int i = 0; i < nb_keepers; ++i) // settings 633 for (int i = 0; i < nb_keepers; ++i) {
690 {
691 // note that we will leak K if we raise an error later 634 // note that we will leak K if we raise an error later
692 KeeperState const K{ create_state(U, L_) }; 635 KeeperState const K{ create_state(U_, L_) }; // L_: settings K:
693 if (K == nullptr) 636 if (K == nullptr) {
694 {
695 raise_luaL_error(L_, "init_keepers() failed while creating keeper states; out of memory"); 637 raise_luaL_error(L_, "init_keepers() failed while creating keeper states; out of memory");
696 } 638 }
697 639
698 U->keepers->keeper_array[i].L = K; 640 U_->keepers->keeper_array[i].L = K;
699 641
700 if (U->keepers->gc_threshold >= 0) 642 if (U_->keepers->gc_threshold >= 0) {
701 {
702 lua_gc(K, LUA_GCSTOP, 0); 643 lua_gc(K, LUA_GCSTOP, 0);
703 } 644 }
704 645
705 STACK_CHECK_START_ABS(K, 0); 646 STACK_CHECK_START_ABS(K, 0);
706 647
707 // copy the universe pointer in the keeper itself 648 // copy the universe pointer in the keeper itself
708 universe_store(K, U); 649 universe_store(K, U_);
709 STACK_CHECK(K, 0); 650 STACK_CHECK(K, 0);
710 651
711 // make sure 'package' is initialized in keeper states, so that we have require() 652 // make sure 'package' is initialized in keeper states, so that we have require()
712 // this because this is needed when transferring deep userdata object 653 // this because this is needed when transferring deep userdata object
713 luaL_requiref(K, "package", luaopen_package, 1); // settings package 654 luaL_requiref(K, "package", luaopen_package, 1); // L_: settings K: package
714 lua_pop(K, 1); // settings 655 lua_pop(K, 1); // L_: settings K:
715 STACK_CHECK(K, 0); 656 STACK_CHECK(K, 0);
716 serialize_require(DEBUGSPEW_PARAM_COMMA(U) K); 657 serialize_require(DEBUGSPEW_PARAM_COMMA(U_) K);
717 STACK_CHECK(K, 0); 658 STACK_CHECK(K, 0);
718 659
719 // copy package.path and package.cpath from the source state (TODO: use _R._LOADED.package instead of _G.package) 660 // copy package.path and package.cpath from the source state (TODO: use _R._LOADED.package instead of _G.package)
720 lua_getglobal(L_, "package"); // settings package 661 lua_getglobal(L_, "package"); // L_: settings package K:
721 if (!lua_isnil(L_, -1)) 662 if (!lua_isnil(L_, -1)) {
722 {
723 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately 663 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately
724 InterCopyContext c{ U, DestState{ K }, SourceState{ L_ }, {}, SourceIndex{ lua_absindex(L_, -1) }, {}, LookupMode::ToKeeper, {} }; 664 InterCopyContext c{ U_, DestState{ K }, SourceState{ L_ }, {}, SourceIndex{ lua_absindex(L_, -1) }, {}, LookupMode::ToKeeper, {} };
725 if (c.inter_copy_package() != InterCopyResult::Success) 665 if (c.inter_copy_package() != InterCopyResult::Success) { // L_: settings ... error_msg K:
726 {
727 // if something went wrong, the error message is at the top of the stack 666 // if something went wrong, the error message is at the top of the stack
728 lua_remove(L_, -2); // settings error_msg 667 lua_remove(L_, -2); // L_: settings error_msg
729 raise_lua_error(L_); 668 raise_lua_error(L_);
730 } 669 }
731 } 670 }
732 lua_pop(L_, 1); // settings 671 lua_pop(L_, 1); // L_: settings K:
733 STACK_CHECK(L_, 0); 672 STACK_CHECK(L_, 0);
734 STACK_CHECK(K, 0); 673 STACK_CHECK(K, 0);
735 674
736 // attempt to call on_state_create(), if we have one and it is a C function 675 // attempt to call on_state_create(), if we have one and it is a C function
737 // (only support a C function because we can't transfer executable Lua code in keepers) 676 // (only support a C function because we can't transfer executable Lua code in keepers)
738 // will raise an error in L_ in case of problem 677 // will raise an error in L_ in case of problem
739 call_on_state_create(U, K, L_, LookupMode::ToKeeper); 678 call_on_state_create(U_, K, L_, LookupMode::ToKeeper);
740 679
741 // to see VM name in Decoda debugger 680 // to see VM name in Decoda debugger
742 lua_pushfstring(K, "Keeper #%d", i + 1); // "Keeper #n" 681 lua_pushfstring(K, "Keeper #%d", i + 1); // L_: settings K: "Keeper #n"
743 lua_setglobal(K, "decoda_name"); // 682 lua_setglobal(K, "decoda_name"); // L_: settings K:
744 // create the fifos table in the keeper state 683 // create the fifos table in the keeper state
745 kFifosRegKey.setValue(K, [](lua_State* L_) { lua_newtable(L_); }); 684 kFifosRegKey.setValue(K, [](lua_State* L_) { lua_newtable(L_); }); // L_: settings K:
746 STACK_CHECK(K, 0); 685 STACK_CHECK(K, 0);
747 } 686 }
748 STACK_CHECK(L_, 0); 687 STACK_CHECK(L_, 0);
@@ -754,8 +693,7 @@ Keeper* Linda::acquireKeeper() const
754{ 693{
755 int const nbKeepers{ U->keepers->nb_keepers }; 694 int const nbKeepers{ U->keepers->nb_keepers };
756 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) 695 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers)
757 if (nbKeepers) 696 if (nbKeepers) {
758 {
759 Keeper* const K{ &U->keepers->keeper_array[m_keeper_index] }; 697 Keeper* const K{ &U->keepers->keeper_array[m_keeper_index] };
760 K->m_mutex.lock(); 698 K->m_mutex.lock();
761 return K; 699 return K;
@@ -767,8 +705,7 @@ Keeper* Linda::acquireKeeper() const
767 705
768void Linda::releaseKeeper(Keeper* K_) const 706void Linda::releaseKeeper(Keeper* K_) const
769{ 707{
770 if (K_) // can be nullptr if we tried to acquire during shutdown 708 if (K_) { // can be nullptr if we tried to acquire during shutdown
771 {
772 assert(K_ == &U->keepers->keeper_array[m_keeper_index]); 709 assert(K_ == &U->keepers->keeper_array[m_keeper_index]);
773 K_->m_mutex.unlock(); 710 K_->m_mutex.unlock();
774 } 711 }
@@ -779,20 +716,14 @@ void Linda::releaseKeeper(Keeper* K_) const
779void keeper_toggle_nil_sentinels(lua_State* L_, int start_, LookupMode const mode_) 716void keeper_toggle_nil_sentinels(lua_State* L_, int start_, LookupMode const mode_)
780{ 717{
781 int const n{ lua_gettop(L_) }; 718 int const n{ lua_gettop(L_) };
782 for (int i = start_; i <= n; ++i) 719 for (int i = start_; i <= n; ++i) {
783 { 720 if (mode_ == LookupMode::ToKeeper) {
784 if (mode_ == LookupMode::ToKeeper) 721 if (lua_isnil(L_, i)) {
785 {
786 if (lua_isnil(L_, i))
787 {
788 kNilSentinel.pushKey(L_); 722 kNilSentinel.pushKey(L_);
789 lua_replace(L_, i); 723 lua_replace(L_, i);
790 } 724 }
791 } 725 } else {
792 else 726 if (kNilSentinel.equals(L_, i)) {
793 {
794 if (kNilSentinel.equals(L_, i))
795 {
796 lua_pushnil(L_); 727 lua_pushnil(L_);
797 lua_replace(L_, i); 728 lua_replace(L_, i);
798 } 729 }
@@ -803,65 +734,57 @@ void keeper_toggle_nil_sentinels(lua_State* L_, int start_, LookupMode const mod
803// ################################################################################################# 734// #################################################################################################
804 735
805/* 736/*
806* Call a function ('func_name') in the keeper state, and pass on the returned 737 * Call a function ('func_name') in the keeper state, and pass on the returned
807* values to 'L'. 738 * values to 'L'.
808* 739 *
809* 'linda': deep Linda pointer (used only as a unique table key, first parameter) 740 * 'linda': deep Linda pointer (used only as a unique table key, first parameter)
810* 'starting_index': first of the rest of parameters (none if 0) 741 * 'starting_index': first of the rest of parameters (none if 0)
811* 742 *
812* Returns: number of return values (pushed to 'L'), unset in case of error 743 * Returns: number of return values (pushed to 'L'), unset in case of error
813*/ 744 */
814KeeperCallResult keeper_call(Universe* U, KeeperState K, keeper_api_t func_, lua_State* L_, void* linda_, int starting_index_) 745KeeperCallResult keeper_call(Universe* U_, KeeperState K_, keeper_api_t func_, lua_State* L_, void* linda_, int starting_index_)
815{ 746{
816 KeeperCallResult result; 747 KeeperCallResult result;
817 int const args{ starting_index_ ? (lua_gettop(L_) - starting_index_ + 1) : 0 }; 748 int const args{ starting_index_ ? (lua_gettop(L_) - starting_index_ + 1) : 0 }; // L: ... args... K_:
818 int const top_K{ lua_gettop(K) }; 749 int const top_K{ lua_gettop(K_) };
819 // if we didn't do anything wrong, the keeper stack should be clean 750 // if we didn't do anything wrong, the keeper stack should be clean
820 LUA_ASSERT(L_, lua_gettop(K) == 0); 751 LUA_ASSERT(L_, top_K == 0);
821 752
822 STACK_GROW(K, 2); 753 STACK_GROW(K_, 2);
823 PUSH_KEEPER_FUNC(K, func_); // func_ 754 PUSH_KEEPER_FUNC(K_, func_); // L: ... args... K_: func_
824 lua_pushlightuserdata(K, linda_); // func_ linda 755 lua_pushlightuserdata(K_, linda_); // L: ... args... K_: func_ linda
825 if ( 756 if (
826 (args == 0) || 757 (args == 0) ||
827 (InterCopyContext{ U, DestState{ K }, SourceState{ L_ }, {}, {}, {}, LookupMode::ToKeeper, {} }.inter_copy(args) == InterCopyResult::Success) 758 (InterCopyContext{ U_, DestState{ K_ }, SourceState{ L_ }, {}, {}, {}, LookupMode::ToKeeper, {} }.inter_copy(args) == InterCopyResult::Success)
828 ) 759 ) { // L: ... args... K_: func_ linda args...
829 { // func_ linda args... 760 lua_call(K_, 1 + args, LUA_MULTRET); // L: ... args... K_: result...
830 lua_call(K, 1 + args, LUA_MULTRET); // result... 761 int const retvals{ lua_gettop(K_) - top_K };
831 int const retvals{ lua_gettop(K) - top_K };
832 // note that this can raise a lua error while the keeper state (and its mutex) is acquired 762 // note that this can raise a lua error while the keeper state (and its mutex) is acquired
833 // this may interrupt a lane, causing the destruction of the underlying OS thread 763 // this may interrupt a lane, causing the destruction of the underlying OS thread
834 // after this, another lane making use of this keeper can get an error code from the mutex-locking function 764 // after this, another lane making use of this keeper can get an error code from the mutex-locking function
835 // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) 765 // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread)
836 if ( 766 if (
837 (retvals == 0) || 767 (retvals == 0) ||
838 (InterCopyContext{ U, DestState{ L_ }, SourceState{ K }, {}, {}, {}, LookupMode::FromKeeper, {} }.inter_move(retvals) == InterCopyResult::Success) 768 (InterCopyContext{ U_, DestState{ L_ }, SourceState{ K_ }, {}, {}, {}, LookupMode::FromKeeper, {} }.inter_move(retvals) == InterCopyResult::Success)
839 ) // K->L_ 769 ) { // L: ... args... result... K_: result...
840 {
841 result.emplace(retvals); 770 result.emplace(retvals);
842 } 771 }
843 } 772 }
844 // whatever happens, restore the stack to where it was at the origin 773 // whatever happens, restore the stack to where it was at the origin
845 lua_settop(K, top_K); 774 lua_settop(K_, top_K); // L: ... args... result... K_:
846 775
847 // don't do this for this particular function, as it is only called during Linda destruction, and we don't want to raise an error, ever 776 // don't do this for this particular function, as it is only called during Linda destruction, and we don't want to raise an error, ever
848 if (func_ != KEEPER_API(clear)) [[unlikely]] 777 if (func_ != KEEPER_API(clear)) [[unlikely]] {
849 {
850 // since keeper state GC is stopped, let's run a step once in a while if required 778 // since keeper state GC is stopped, let's run a step once in a while if required
851 int const gc_threshold{ U->keepers->gc_threshold }; 779 int const gc_threshold{ U_->keepers->gc_threshold };
852 if (gc_threshold == 0) [[unlikely]] 780 if (gc_threshold == 0) [[unlikely]] {
853 { 781 lua_gc(K_, LUA_GCSTEP, 0);
854 lua_gc(K, LUA_GCSTEP, 0); 782 } else if (gc_threshold > 0) [[likely]] {
855 } 783 int const gc_usage{ lua_gc(K_, LUA_GCCOUNT, 0) };
856 else if (gc_threshold > 0) [[likely]] 784 if (gc_usage >= gc_threshold) {
857 { 785 lua_gc(K_, LUA_GCCOLLECT, 0);
858 int const gc_usage{ lua_gc(K, LUA_GCCOUNT, 0) }; 786 int const gc_usage_after{ lua_gc(K_, LUA_GCCOUNT, 0) };
859 if (gc_usage >= gc_threshold) 787 if (gc_usage_after > gc_threshold) [[unlikely]] {
860 {
861 lua_gc(K, LUA_GCCOLLECT, 0);
862 int const gc_usage_after{ lua_gc(K, LUA_GCCOUNT, 0) };
863 if (gc_usage_after > gc_threshold) [[unlikely]]
864 {
865 raise_luaL_error(L_, "Keeper GC threshold is too low, need at least %d", gc_usage_after); 788 raise_luaL_error(L_, "Keeper GC threshold is too low, need at least %d", gc_usage_after);
866 } 789 }
867 } 790 }