aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compat.cpp5
-rw-r--r--src/keeper.cpp756
-rw-r--r--src/keeper.h42
-rw-r--r--src/lanes.cpp2
-rw-r--r--src/macros_and_utils.h7
-rw-r--r--src/platform.h1
-rw-r--r--tests/fifo.lua35
7 files changed, 448 insertions, 400 deletions
diff --git a/src/compat.cpp b/src/compat.cpp
index 19159a9..47fe37e 100644
--- a/src/compat.cpp
+++ b/src/compat.cpp
@@ -51,8 +51,10 @@ void* lua_newuserdatauv( lua_State* L, size_t sz, int nuvalue)
51 return lua_newuserdata( L, sz); 51 return lua_newuserdata( L, sz);
52} 52}
53 53
54int lua_getiuservalue( lua_State* L, int idx, int n) 54// push on stack uservalue #n of full userdata at idx
55int lua_getiuservalue(lua_State* L, int idx, int n)
55{ 56{
57 // full userdata can have only 1 uservalue before 5.4
56 if( n > 1) 58 if( n > 1)
57 { 59 {
58 lua_pushnil( L); 60 lua_pushnil( L);
@@ -76,6 +78,7 @@ int lua_getiuservalue( lua_State* L, int idx, int n)
76 return lua_type( L, -1); 78 return lua_type( L, -1);
77} 79}
78 80
81// pop stack top, sets it a uservalue #n of full userdata at idx
79int lua_setiuservalue( lua_State* L, int idx, int n) 82int lua_setiuservalue( lua_State* L, int idx, int n)
80{ 83{
81 if( n > 1 84 if( n > 1
diff --git a/src/keeper.cpp b/src/keeper.cpp
index c886718..0cb1a94 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -1,6 +1,6 @@
1/* 1/*
2 -- 2 --
3 -- KEEPER.C 3 -- KEEPER.CPP
4 -- 4 --
5 -- Keeper state logic 5 -- Keeper state logic
6 -- 6 --
@@ -14,7 +14,7 @@
14 --[[ 14 --[[
15 =============================================================================== 15 ===============================================================================
16 16
17 Copyright (C) 2011-2013 Benoit Germain <bnt.germain@gmail.com> 17 Copyright (C) 2011-2023 Benoit Germain <bnt.germain@gmail.com>
18 18
19 Permission is hereby granted, free of charge, to any person obtaining a copy 19 Permission is hereby granted, free of charge, to any person obtaining a copy
20 of this software and associated documentation files (the "Software"), to deal 20 of this software and associated documentation files (the "Software"), to deal
@@ -37,319 +37,324 @@
37 =============================================================================== 37 ===============================================================================
38 ]]-- 38 ]]--
39 */ 39 */
40
41#include <string.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <ctype.h>
45#include <assert.h>
46
47#include "keeper.h" 40#include "keeper.h"
41
48#include "compat.h" 42#include "compat.h"
49#include "tools.h"
50#include "state.h" 43#include "state.h"
51#include "universe.h" 44#include "tools.h"
52#include "uniquekey.h" 45#include "uniquekey.h"
46#include "universe.h"
53 47
54//################################################################################### 48#include <algorithm>
55// Keeper implementation 49#include <cassert>
56//###################################################################################
57 50
58#ifndef __min 51// ###################################################################################
59#define __min( a, b) (((a) < (b)) ? (a) : (b)) 52// Keeper implementation
60#endif // __min 53// ###################################################################################
61 54
62struct keeper_fifo 55struct keeper_fifo
63{ 56{
64 lua_Integer first; 57 int first{ 1 };
65 lua_Integer count; 58 int count{ 0 };
66 lua_Integer limit; 59 int limit{ -1 };
67}; 60};
68 61
69static int const CONTENTS_TABLE = 1; 62static constexpr int CONTENTS_TABLE{ 1 };
63
64// ##################################################################################################
70 65
71// replaces the fifo ud by its uservalue on the stack 66// replaces the fifo ud by its uservalue on the stack
72static keeper_fifo* prepare_fifo_access( lua_State* L, int idx_) 67static keeper_fifo* prepare_fifo_access(lua_State* L, int idx_)
73{ 68{
74 keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx_); 69 keeper_fifo* const fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, idx_)) };
75 if( fifo != nullptr) 70 if (fifo != nullptr)
76 { 71 {
77 idx_ = lua_absindex( L, idx_); 72 idx_ = lua_absindex(L, idx_);
78 STACK_GROW( L, 1); 73 STACK_GROW(L, 1);
79 // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around 74 // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around
80 lua_getiuservalue( L, idx_, CONTENTS_TABLE); 75 lua_getiuservalue(L, idx_, CONTENTS_TABLE);
81 lua_replace( L, idx_); 76 lua_replace(L, idx_);
82 } 77 }
83 return fifo; 78 return fifo;
84} 79}
85 80
81// ##################################################################################################
82
86// in: nothing 83// in: nothing
87// out: { first = 1, count = 0, limit = -1} 84// out: { first = 1, count = 0, limit = -1}
88static void fifo_new( lua_State* L) 85static void fifo_new(lua_State* L)
89{ 86{
90 keeper_fifo* fifo; 87 keeper_fifo* fifo;
91 STACK_GROW( L, 2); 88 STACK_GROW(L, 2);
92 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents 89 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
93 fifo = (keeper_fifo*)lua_newuserdatauv( L, sizeof( keeper_fifo), 1); 90 fifo = (keeper_fifo*) lua_newuserdatauv(L, sizeof(keeper_fifo), 1);
94 fifo->first = 1; 91 fifo->keeper_fifo::keeper_fifo();
95 fifo->count = 0; 92 lua_newtable(L);
96 fifo->limit = -1; 93 lua_setiuservalue(L, -2, CONTENTS_TABLE);
97 lua_newtable( L);
98 lua_setiuservalue( L, -2, CONTENTS_TABLE);
99} 94}
100 95
96// ##################################################################################################
97
101// in: expect fifo ... on top of the stack 98// in: expect fifo ... on top of the stack
102// out: nothing, removes all pushed values from the stack 99// out: nothing, removes all pushed values from the stack
103static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) 100static void fifo_push(lua_State* L, keeper_fifo* fifo_, int count_)
104{ 101{
105 int const idx = lua_gettop( L) - (int) count_; 102 int const idx{ lua_gettop(L) - count_ };
106 lua_Integer start = fifo_->first + fifo_->count - 1; 103 int const start{ fifo_->first + fifo_->count - 1 };
107 lua_Integer i;
108 // pop all additional arguments, storing them in the fifo 104 // pop all additional arguments, storing them in the fifo
109 for( i = count_; i >= 1; -- i) 105 for (int i = count_; i >= 1; --i)
110 { 106 {
111 // store in the fifo the value at the top of the stack at the specified index, popping it from the stack 107 // store in the fifo the value at the top of the stack at the specified index, popping it from the stack
112 lua_rawseti( L, idx, (int)(start + i)); 108 lua_rawseti(L, idx, start + i);
113 } 109 }
114 fifo_->count += count_; 110 fifo_->count += count_;
115} 111}
116 112
113// ##################################################################################################
114
117// in: fifo 115// in: fifo
118// out: ...|nothing 116// out: ...|nothing
119// expects exactly 1 value on the stack! 117// expects exactly 1 value on the stack!
120// currently only called with a count of 1, but this may change in the future 118// currently only called with a count of 1, but this may change in the future
121// function assumes that there is enough data in the fifo to satisfy the request 119// function assumes that there is enough data in the fifo to satisfy the request
122static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) 120static void fifo_peek(lua_State* L, keeper_fifo* fifo_, int count_)
123{ 121{
124 lua_Integer i; 122 STACK_GROW(L, count_);
125 STACK_GROW( L, count_); 123 for (int i = 0; i < count_; ++i)
126 for( i = 0; i < count_; ++ i)
127 { 124 {
128 lua_rawgeti( L, 1, (int)( fifo_->first + i)); 125 lua_rawgeti(L, 1, (fifo_->first + i));
129 } 126 }
130} 127}
131 128
129// ##################################################################################################
130
132// in: fifo 131// in: fifo
133// out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) 132// out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number)
134static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) 133static void fifo_pop( lua_State* L, keeper_fifo* fifo_, int count_)
135{ 134{
136 int const fifo_idx = lua_gettop( L); // ... fifo 135 int const fifo_idx = lua_gettop(L); // ... fifo
137 int i;
138 // each iteration pushes a value on the stack! 136 // each iteration pushes a value on the stack!
139 STACK_GROW( L, count_ + 2); 137 STACK_GROW(L, count_ + 2);
140 // skip first item, we will push it last 138 // skip first item, we will push it last
141 for( i = 1; i < count_; ++ i) 139 for (int i = 1; i < count_; ++i)
142 { 140 {
143 int const at = (int)( fifo_->first + i); 141 int const at{ fifo_->first + i };
144 // push item on the stack 142 // push item on the stack
145 lua_rawgeti( L, fifo_idx, at); // ... fifo val 143 lua_rawgeti(L, fifo_idx, at); // ... fifo val
146 // remove item from the fifo 144 // remove item from the fifo
147 lua_pushnil( L); // ... fifo val nil 145 lua_pushnil(L); // ... fifo val nil
148 lua_rawseti( L, fifo_idx, at); // ... fifo val 146 lua_rawseti(L, fifo_idx, at); // ... fifo val
149 } 147 }
150 // now process first item 148 // now process first item
151 { 149 {
152 int const at = (int)( fifo_->first); 150 int const at{ fifo_->first };
153 lua_rawgeti( L, fifo_idx, at); // ... fifo vals val 151 lua_rawgeti(L, fifo_idx, at); // ... fifo vals val
154 lua_pushnil( L); // ... fifo vals val nil 152 lua_pushnil(L); // ... fifo vals val nil
155 lua_rawseti( L, fifo_idx, at); // ... fifo vals val 153 lua_rawseti(L, fifo_idx, at); // ... fifo vals val
156 lua_replace( L, fifo_idx); // ... vals 154 lua_replace(L, fifo_idx); // ... vals
157 } 155 }
158 { 156 {
159 // avoid ever-growing indexes by resetting each time we detect the fifo is empty 157 // avoid ever-growing indexes by resetting each time we detect the fifo is empty
160 lua_Integer const new_count = fifo_->count - count_; 158 int const new_count{ fifo_->count - count_ };
161 fifo_->first = (new_count == 0) ? 1 : (fifo_->first + count_); 159 fifo_->first = (new_count == 0) ? 1 : (fifo_->first + count_);
162 fifo_->count = new_count; 160 fifo_->count = new_count;
163 } 161 }
164} 162}
165 163
164// ##################################################################################################
165
166// in: linda_ud expected at *absolute* stack slot idx 166// in: linda_ud expected at *absolute* stack slot idx
167// out: fifos[ud] 167// out: fifos[ud]
168// crc64/we of string "FIFOS_KEY" generated at http://www.nitrxgen.net/hashgen/ 168// crc64/we of string "FIFOS_KEY" generated at http://www.nitrxgen.net/hashgen/
169static constexpr UniqueKey FIFOS_KEY{ 0xdce50bbc351cd465ull }; 169static constexpr UniqueKey FIFOS_KEY{ 0xdce50bbc351cd465ull };
170static void push_table( lua_State* L, int idx_) 170static void push_table(lua_State* L, int idx_)
171{ 171{
172 STACK_GROW( L, 4); 172 STACK_GROW(L, 4);
173 STACK_CHECK( L, 0); 173 STACK_CHECK(L, 0);
174 idx_ = lua_absindex( L, idx_); 174 idx_ = lua_absindex(L, idx_);
175 FIFOS_KEY.query_registry(L); // ud fifos 175 FIFOS_KEY.query_registry(L); // ud fifos
176 lua_pushvalue( L, idx_); // ud fifos ud 176 lua_pushvalue(L, idx_); // ud fifos ud
177 lua_rawget( L, -2); // ud fifos fifos[ud] 177 lua_rawget(L, -2); // ud fifos fifos[ud]
178 STACK_MID( L, 2); 178 STACK_MID(L, 2);
179 if( lua_isnil( L, -1)) 179 if (lua_isnil(L, -1))
180 { 180 {
181 lua_pop( L, 1); // ud fifos 181 lua_pop(L, 1); // ud fifos
182 // add a new fifos table for this linda 182 // add a new fifos table for this linda
183 lua_newtable( L); // ud fifos fifos[ud] 183 lua_newtable(L); // ud fifos fifos[ud]
184 lua_pushvalue( L, idx_); // ud fifos fifos[ud] ud 184 lua_pushvalue(L, idx_); // ud fifos fifos[ud] ud
185 lua_pushvalue( L, -2); // ud fifos fifos[ud] ud fifos[ud] 185 lua_pushvalue(L, -2); // ud fifos fifos[ud] ud fifos[ud]
186 lua_rawset( L, -4); // ud fifos fifos[ud] 186 lua_rawset(L, -4); // ud fifos fifos[ud]
187 } 187 }
188 lua_remove( L, -2); // ud fifos[ud] 188 lua_remove(L, -2); // ud fifos[ud]
189 STACK_END( L, 1); 189 STACK_END(L, 1);
190} 190}
191 191
192int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) 192// ##################################################################################################
193
194int keeper_push_linda_storage(Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_)
193{ 195{
194 Keeper* const K = which_keeper( U->keepers, magic_); 196 Keeper* const K = which_keeper( U->keepers, magic_);
195 lua_State* const KL = K ? K->L : nullptr; 197 lua_State* const KL = K ? K->L : nullptr;
196 if( KL == nullptr) return 0; 198 if( KL == nullptr) return 0;
197 STACK_GROW( KL, 4); 199 STACK_GROW(KL, 4);
198 STACK_CHECK( KL, 0); 200 STACK_CHECK(KL, 0);
199 FIFOS_KEY.query_registry(KL); // fifos 201 FIFOS_KEY.query_registry(KL); // fifos
200 lua_pushlightuserdata( KL, ptr_); // fifos ud 202 lua_pushlightuserdata(KL, ptr_); // fifos ud
201 lua_rawget( KL, -2); // fifos storage 203 lua_rawget(KL, -2); // fifos storage
202 lua_remove( KL, -2); // storage 204 lua_remove(KL, -2); // storage
203 if( !lua_istable( KL, -1)) 205 if( !lua_istable(KL, -1))
204 { 206 {
205 lua_pop( KL, 1); // 207 lua_pop(KL, 1); //
206 STACK_MID( KL, 0); 208 STACK_MID(KL, 0);
207 return 0; 209 return 0;
208 } 210 }
209 // move data from keeper to destination state KEEPER MAIN 211 // move data from keeper to destination state KEEPER MAIN
210 lua_pushnil( KL); // storage nil 212 lua_pushnil(KL); // storage nil
211 STACK_GROW( L, 5); 213 STACK_GROW(L, 5);
212 STACK_CHECK( L, 0); 214 STACK_CHECK(L, 0);
213 lua_newtable( L); // out 215 lua_newtable(L); // out
214 while( lua_next( KL, -2)) // storage key fifo 216 while( lua_next(KL, -2)) // storage key fifo
215 { 217 {
216 keeper_fifo* fifo = prepare_fifo_access( KL, -1); // storage key fifo 218 keeper_fifo* fifo = prepare_fifo_access(KL, -1); // storage key fifo
217 lua_pushvalue( KL, -2); // storage key fifo key 219 lua_pushvalue(KL, -2); // storage key fifo key
218 luaG_inter_move( U, KL, L, 1, eLM_FromKeeper); // storage key fifo // out key 220 luaG_inter_move(U, KL, L, 1, eLM_FromKeeper); // storage key fifo // out key
219 STACK_MID( L, 2); 221 STACK_MID(L, 2);
220 lua_newtable( L); // out key keyout 222 lua_newtable(L); // out key keyout
221 luaG_inter_move( U, KL, L, 1, eLM_FromKeeper); // storage key // out key keyout fifo 223 luaG_inter_move(U, KL, L, 1, eLM_FromKeeper); // storage key // out key keyout fifo
222 lua_pushinteger( L, fifo->first); // out key keyout fifo first 224 lua_pushinteger(L, fifo->first); // out key keyout fifo first
223 STACK_MID( L, 5); 225 STACK_MID(L, 5);
224 lua_setfield( L, -3, "first"); // out key keyout fifo 226 lua_setfield(L, -3, "first"); // out key keyout fifo
225 lua_pushinteger( L, fifo->count); // out key keyout fifo count 227 lua_pushinteger(L, fifo->count); // out key keyout fifo count
226 STACK_MID( L, 5); 228 STACK_MID(L, 5);
227 lua_setfield( L, -3, "count"); // out key keyout fifo 229 lua_setfield(L, -3, "count"); // out key keyout fifo
228 lua_pushinteger( L, fifo->limit); // out key keyout fifo limit 230 lua_pushinteger(L, fifo->limit); // out key keyout fifo limit
229 STACK_MID( L, 5); 231 STACK_MID(L, 5);
230 lua_setfield( L, -3, "limit"); // out key keyout fifo 232 lua_setfield(L, -3, "limit"); // out key keyout fifo
231 lua_setfield( L, -2, "fifo"); // out key keyout 233 lua_setfield(L, -2, "fifo"); // out key keyout
232 lua_rawset( L, -3); // out 234 lua_rawset(L, -3); // out
233 STACK_MID( L, 1); 235 STACK_MID(L, 1);
234 } 236 }
235 STACK_END( L, 1); 237 STACK_END(L, 1);
236 lua_pop( KL, 1); // 238 lua_pop(KL, 1); //
237 STACK_END( KL, 0); 239 STACK_END(KL, 0);
238 return 1; 240 return 1;
239} 241}
240 242
243// ##################################################################################################
244
241// in: linda_ud 245// in: linda_ud
242int keepercall_clear( lua_State* L) 246int keepercall_clear(lua_State* L)
243{ 247{
244 STACK_GROW( L, 3); 248 STACK_GROW(L, 3);
245 STACK_CHECK( L, 0); 249 STACK_CHECK(L, 0);
246 FIFOS_KEY.query_registry(L); // ud fifos 250 FIFOS_KEY.query_registry(L); // ud fifos
247 lua_pushvalue( L, 1); // ud fifos ud 251 lua_pushvalue(L, 1); // ud fifos ud
248 lua_pushnil( L); // ud fifos ud nil 252 lua_pushnil(L); // ud fifos ud nil
249 lua_rawset( L, -3); // ud fifos 253 lua_rawset(L, -3); // ud fifos
250 lua_pop( L, 1); // ud 254 lua_pop(L, 1); // ud
251 STACK_END( L, 0); 255 STACK_END(L, 0);
252 return 0; 256 return 0;
253} 257}
254 258
259// ##################################################################################################
255 260
256// in: linda_ud, key, ... 261// in: linda_ud, key, ...
257// out: true|false 262// out: true|false
258int keepercall_send( lua_State* L) 263int keepercall_send(lua_State* L)
259{ 264{
260 keeper_fifo* fifo; 265 int const n{ lua_gettop(L) - 2 };
261 int n = lua_gettop( L) - 2; 266 push_table(L, 1); // ud key ... fifos
262 push_table( L, 1); // ud key ... fifos
263 // get the fifo associated to this key in this linda, create it if it doesn't exist 267 // get the fifo associated to this key in this linda, create it if it doesn't exist
264 lua_pushvalue( L, 2); // ud key ... fifos key 268 lua_pushvalue(L, 2); // ud key ... fifos key
265 lua_rawget( L, -2); // ud key ... fifos fifo 269 lua_rawget(L, -2); // ud key ... fifos fifo
266 if( lua_isnil( L, -1)) 270 if( lua_isnil(L, -1))
267 { 271 {
268 lua_pop( L, 1); // ud key ... fifos 272 lua_pop(L, 1); // ud key ... fifos
269 fifo_new( L); // ud key ... fifos fifo 273 fifo_new(L); // ud key ... fifos fifo
270 lua_pushvalue( L, 2); // ud key ... fifos fifo key 274 lua_pushvalue(L, 2); // ud key ... fifos fifo key
271 lua_pushvalue( L, -2); // ud key ... fifos fifo key fifo 275 lua_pushvalue(L, -2); // ud key ... fifos fifo key fifo
272 lua_rawset( L, -4); // ud key ... fifos fifo 276 lua_rawset(L, -4); // ud key ... fifos fifo
273 } 277 }
274 lua_remove( L, -2); // ud key ... fifo 278 lua_remove(L, -2); // ud key ... fifo
275 fifo = (keeper_fifo*) lua_touserdata( L, -1); 279 keeper_fifo* fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, -1)) };
276 if( fifo->limit >= 0 && fifo->count + n > fifo->limit) 280 if( fifo->limit >= 0 && fifo->count + n > fifo->limit)
277 { 281 {
278 lua_settop( L, 0); // 282 lua_settop(L, 0); //
279 lua_pushboolean( L, 0); // false 283 lua_pushboolean(L, 0); // false
280 } 284 }
281 else 285 else
282 { 286 {
283 fifo = prepare_fifo_access( L, -1); 287 fifo = prepare_fifo_access(L, -1);
284 lua_replace( L, 2); // ud fifo ... 288 lua_replace(L, 2); // ud fifo ...
285 fifo_push( L, fifo, n); // ud fifo 289 fifo_push(L, fifo, n); // ud fifo
286 lua_settop( L, 0); // 290 lua_settop(L, 0); //
287 lua_pushboolean( L, 1); // true 291 lua_pushboolean(L, 1); // true
288 } 292 }
289 return 1; 293 return 1;
290} 294}
291 295
296// ##################################################################################################
297
292// in: linda_ud, key [, key]? 298// in: linda_ud, key [, key]?
293// out: (key, val) or nothing 299// out: (key, val) or nothing
294int keepercall_receive( lua_State* L) 300int keepercall_receive(lua_State* L)
295{ 301{
296 int top = lua_gettop( L); 302 int const top{ lua_gettop(L) };
297 int i; 303 push_table(L, 1); // ud keys fifos
298 push_table( L, 1); // ud keys fifos 304 lua_replace(L, 1); // fifos keys
299 lua_replace( L, 1); // fifos keys 305 for (int i = 2; i <= top; ++i)
300 for( i = 2; i <= top; ++ i)
301 { 306 {
302 keeper_fifo* fifo; 307 lua_pushvalue(L, i); // fifos keys key[i]
303 lua_pushvalue( L, i); // fifos keys key[i] 308 lua_rawget(L, 1); // fifos keys fifo
304 lua_rawget( L, 1); // fifos keys fifo 309 keeper_fifo* const fifo{ prepare_fifo_access(L, -1) }; // fifos keys fifo
305 fifo = prepare_fifo_access( L, -1); // fifos keys fifo 310 if (fifo != nullptr && fifo->count > 0)
306 if( fifo != nullptr && fifo->count > 0)
307 { 311 {
308 fifo_pop( L, fifo, 1); // fifos keys val 312 fifo_pop(L, fifo, 1); // fifos keys val
309 if( !lua_isnil( L, -1)) 313 if (!lua_isnil(L, -1))
310 { 314 {
311 lua_replace( L, 1); // val keys 315 lua_replace(L, 1); // val keys
312 lua_settop( L, i); // val keys key[i] 316 lua_settop(L, i); // val keys key[i]
313 if( i != 2) 317 if (i != 2)
314 { 318 {
315 lua_replace( L, 2); // val key keys 319 lua_replace(L, 2); // val key keys
316 lua_settop( L, 2); // val key 320 lua_settop(L, 2); // val key
317 } 321 }
318 lua_insert( L, 1); // key, val 322 lua_insert(L, 1); // key, val
319 return 2; 323 return 2;
320 } 324 }
321 } 325 }
322 lua_settop( L, top); // data keys 326 lua_settop(L, top); // data keys
323 } 327 }
324 // nothing to receive 328 // nothing to receive
325 return 0; 329 return 0;
326} 330}
327 331
328//in: linda_ud key mincount [maxcount] 332// ##################################################################################################
329int keepercall_receive_batched( lua_State* L) 333
334// in: linda_ud key mincount [maxcount]
335int keepercall_receive_batched(lua_State* L)
330{ 336{
331 lua_Integer const min_count = lua_tointeger( L, 3); 337 int const min_count{ static_cast<int>(lua_tointeger(L, 3)) };
332 if( min_count > 0) 338 if( min_count > 0)
333 { 339 {
334 keeper_fifo* fifo; 340 int const max_count{ static_cast<int>(luaL_optinteger(L, 4, min_count)) };
335 lua_Integer const max_count = luaL_optinteger( L, 4, min_count); 341 lua_settop(L, 2); // ud key
336 lua_settop( L, 2); // ud key 342 lua_insert(L, 1); // key ud
337 lua_insert( L, 1); // key ud 343 push_table(L, 2); // key ud fifos
338 push_table( L, 2); // key ud fifos 344 lua_remove(L, 2); // key fifos
339 lua_remove( L, 2); // key fifos 345 lua_pushvalue(L, 1); // key fifos key
340 lua_pushvalue( L, 1); // key fifos key 346 lua_rawget(L, 2); // key fifos fifo
341 lua_rawget( L, 2); // key fifos fifo 347 lua_remove(L, 2); // key fifo
342 lua_remove( L, 2); // key fifo 348 keeper_fifo* const fifo{ prepare_fifo_access(L, 2) }; // key fifo
343 fifo = prepare_fifo_access( L, 2); // key fifo
344 if( fifo != nullptr && fifo->count >= min_count) 349 if( fifo != nullptr && fifo->count >= min_count)
345 { 350 {
346 fifo_pop( L, fifo, __min( max_count, fifo->count)); // key ... 351 fifo_pop(L, fifo, std::min( max_count, fifo->count)); // key ...
347 } 352 }
348 else 353 else
349 { 354 {
350 lua_settop( L, 0); 355 lua_settop(L, 0); //
351 } 356 }
352 return lua_gettop( L); 357 return lua_gettop(L);
353 } 358 }
354 else 359 else
355 { 360 {
@@ -357,35 +362,36 @@ int keepercall_receive_batched( lua_State* L)
357 } 362 }
358} 363}
359 364
365// ##################################################################################################
366
360// in: linda_ud key n 367// in: linda_ud key n
361// out: true or nil 368// out: true or nil
362int keepercall_limit( lua_State* L) 369int keepercall_limit(lua_State* L)
363{ 370{
364 keeper_fifo* fifo; 371 int const limit{ static_cast<int>(lua_tointeger(L, 3)) };
365 lua_Integer limit = lua_tointeger( L, 3); 372 push_table(L, 1); // ud key n fifos
366 push_table( L, 1); // ud key n fifos 373 lua_replace(L, 1); // fifos key n
367 lua_replace( L, 1); // fifos key n 374 lua_pop(L, 1); // fifos key
368 lua_pop( L, 1); // fifos key 375 lua_pushvalue(L, -1); // fifos key key
369 lua_pushvalue( L, -1); // fifos key key 376 lua_rawget(L, -3); // fifos key fifo|nil
370 lua_rawget( L, -3); // fifos key fifo|nil 377 keeper_fifo* fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, -1)) };
371 fifo = (keeper_fifo*) lua_touserdata( L, -1); 378 if (fifo == nullptr)
372 if( fifo == nullptr) 379 { // fifos key nil
373 { // fifos key nil 380 lua_pop(L, 1); // fifos key
374 lua_pop( L, 1); // fifos key 381 fifo_new(L); // fifos key fifo
375 fifo_new( L); // fifos key fifo 382 fifo = static_cast<keeper_fifo*>(lua_touserdata(L, -1));
376 fifo = (keeper_fifo*) lua_touserdata( L, -1); 383 lua_rawset(L, -3); // fifos
377 lua_rawset( L, -3); // fifos
378 } 384 }
379 // remove any clutter on the stack 385 // remove any clutter on the stack
380 lua_settop( L, 0); 386 lua_settop(L, 0);
381 // return true if we decide that blocked threads waiting to write on that key should be awakened 387 // return true if we decide that blocked threads waiting to write on that key should be awakened
382 // this is the case if we detect the key was full but it is no longer the case 388 // this is the case if we detect the key was full but it is no longer the case
383 if( 389 if(
384 ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit 390 ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit
385 && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit 391 && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit
386 ) 392 )
387 { 393 {
388 lua_pushboolean( L, 1); 394 lua_pushboolean(L, 1); // true
389 } 395 }
390 // set the new limit 396 // set the new limit
391 fifo->limit = limit; 397 fifo->limit = limit;
@@ -393,40 +399,41 @@ int keepercall_limit( lua_State* L)
393 return lua_gettop( L); 399 return lua_gettop( L);
394} 400}
395 401
396//in: linda_ud key [[val] ...] 402// ##################################################################################################
403
404// in: linda_ud key [[val] ...]
397//out: true or nil 405//out: true or nil
398int keepercall_set( lua_State* L) 406int keepercall_set(lua_State* L)
399{ 407{
400 bool should_wake_writers{ false }; 408 bool should_wake_writers{ false };
401 STACK_GROW( L, 6); 409 STACK_GROW(L, 6);
402 410
403 // retrieve fifos associated with the linda 411 // retrieve fifos associated with the linda
404 push_table( L, 1); // ud key [val [, ...]] fifos 412 push_table(L, 1); // ud key [val [, ...]] fifos
405 lua_replace( L, 1); // fifos key [val [, ...]] 413 lua_replace(L, 1); // fifos key [val [, ...]]
406 414
407 // make sure we have a value on the stack 415 // make sure we have a value on the stack
408 if( lua_gettop( L) == 2) // fifos key 416 if (lua_gettop(L) == 2) // fifos key
409 { 417 {
410 keeper_fifo* fifo; 418 lua_pushvalue(L, -1); // fifos key key
411 lua_pushvalue( L, -1); // fifos key key 419 lua_rawget(L, 1); // fifos key fifo|nil
412 lua_rawget( L, 1); // fifos key fifo|nil
413 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 420 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
414 fifo = (keeper_fifo*) lua_touserdata( L, -1); 421 keeper_fifo* const fifo{ static_cast<keeper_fifo*>(lua_touserdata(L, -1)) };
415 if( fifo != nullptr) // might be nullptr if we set a nonexistent key to nil 422 if (fifo != nullptr) // might be nullptr if we set a nonexistent key to nil
416 { // fifos key fifo 423 { // fifos key fifo
417 if( fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it 424 if (fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it
418 { 425 {
419 lua_pop( L, 1); // fifos key 426 lua_pop(L, 1); // fifos key
420 lua_pushnil( L); // fifos key nil 427 lua_pushnil(L); // fifos key nil
421 lua_rawset( L, -3); // fifos 428 lua_rawset(L, -3); // fifos
422 } 429 }
423 else 430 else
424 { 431 {
425 // we create room if the fifo was full but it is no longer the case 432 // we create room if the fifo was full but it is no longer the case
426 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); 433 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit);
427 lua_remove( L, -2); // fifos fifo 434 lua_remove(L, -2); // fifos fifo
428 lua_newtable( L); // fifos fifo {} 435 lua_newtable(L); // fifos fifo {}
429 lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos fifo 436 lua_setiuservalue(L, -2, CONTENTS_TABLE); // fifos fifo
430 fifo->first = 1; 437 fifo->first = 1;
431 fifo->count = 0; 438 fifo->count = 0;
432 } 439 }
@@ -434,133 +441,131 @@ int keepercall_set( lua_State* L)
434 } 441 }
435 else // set/replace contents stored at the specified key? 442 else // set/replace contents stored at the specified key?
436 { 443 {
437 lua_Integer count = lua_gettop( L) - 2; // number of items we want to store 444 int const count{ lua_gettop(L) - 2 }; // number of items we want to store
438 keeper_fifo* fifo; // fifos key [val [, ...]] 445 lua_pushvalue(L, 2); // fifos key [val [, ...]] key
439 lua_pushvalue( L, 2); // fifos key [val [, ...]] key 446 lua_rawget(L, 1); // fifos key [val [, ...]] fifo|nil
440 lua_rawget( L, 1); // fifos key [val [, ...]] fifo|nil 447 keeper_fifo* fifo = static_cast<keeper_fifo*>(lua_touserdata( L, -1));
441 fifo = (keeper_fifo*) lua_touserdata( L, -1);
442 if( fifo == nullptr) // can be nullptr if we store a value at a new key 448 if( fifo == nullptr) // can be nullptr if we store a value at a new key
443 { // fifos key [val [, ...]] nil 449 { // fifos key [val [, ...]] nil
444 // no need to wake writers in that case, because a writer can't wait on an inexistent key 450 // no need to wake writers in that case, because a writer can't wait on an inexistent key
445 lua_pop( L, 1); // fifos key [val [, ...]] 451 lua_pop(L, 1); // fifos key [val [, ...]]
446 fifo_new( L); // fifos key [val [, ...]] fifo 452 fifo_new(L); // fifos key [val [, ...]] fifo
447 lua_pushvalue( L, 2); // fifos key [val [, ...]] fifo key 453 lua_pushvalue(L, 2); // fifos key [val [, ...]] fifo key
448 lua_pushvalue( L, -2); // fifos key [val [, ...]] fifo key fifo 454 lua_pushvalue(L, -2); // fifos key [val [, ...]] fifo key fifo
449 lua_rawset( L, 1); // fifos key [val [, ...]] fifo 455 lua_rawset(L, 1); // fifos key [val [, ...]] fifo
450 } 456 }
451 else // the fifo exists, we just want to update its contents 457 else // the fifo exists, we just want to update its contents
452 { // fifos key [val [, ...]] fifo 458 { // fifos key [val [, ...]] fifo
453 // we create room if the fifo was full but it is no longer the case 459 // we create room if the fifo was full but it is no longer the case
454 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit); 460 should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit);
455 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 461 // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
456 lua_newtable( L); // fifos key [val [, ...]] fifo {} 462 lua_newtable(L); // fifos key [val [, ...]] fifo {}
457 lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos key [val [, ...]] fifo 463 lua_setiuservalue(L, -2, CONTENTS_TABLE); // fifos key [val [, ...]] fifo
458 fifo->first = 1; 464 fifo->first = 1;
459 fifo->count = 0; 465 fifo->count = 0;
460 } 466 }
461 fifo = prepare_fifo_access( L, -1); 467 fifo = prepare_fifo_access(L, -1);
462 // move the fifo below the values we want to store 468 // move the fifo below the values we want to store
463 lua_insert( L, 3); // fifos key fifo [val [, ...]] 469 lua_insert(L, 3); // fifos key fifo [val [, ...]]
464 fifo_push( L, fifo, count); // fifos key fifo 470 fifo_push(L, fifo, count); // fifos key fifo
465 } 471 }
466 return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; 472 return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0;
467} 473}
468 474
475// ##################################################################################################
476
469// in: linda_ud key [count] 477// in: linda_ud key [count]
470// out: at most <count> values 478// out: at most <count> values
471int keepercall_get( lua_State* L) 479int keepercall_get(lua_State* L)
472{ 480{
473 keeper_fifo* fifo; 481 int count{ 1 };
474 lua_Integer count = 1; 482 if (lua_gettop(L) == 3) // ud key count
475 if( lua_gettop( L) == 3) // ud key count
476 { 483 {
477 count = lua_tointeger( L, 3); 484 count = static_cast<int>(lua_tointeger(L, 3));
478 lua_pop( L, 1); // ud key 485 lua_pop(L, 1); // ud key
479 } 486 }
480 push_table( L, 1); // ud key fifos 487 push_table(L, 1); // ud key fifos
481 lua_replace( L, 1); // fifos key 488 lua_replace(L, 1); // fifos key
482 lua_rawget( L, 1); // fifos fifo 489 lua_rawget(L, 1); // fifos fifo
483 fifo = prepare_fifo_access( L, -1); // fifos fifo 490 keeper_fifo* const fifo{ prepare_fifo_access(L, -1) }; // fifos fifo
484 if( fifo != nullptr && fifo->count > 0) 491 if (fifo != nullptr && fifo->count > 0)
485 { 492 {
486 lua_remove( L, 1); // fifo 493 lua_remove(L, 1); // fifo
487 count = __min( count, fifo->count); 494 count = std::min(count, fifo->count);
488 // read <count> value off the fifo 495 // read <count> value off the fifo
489 fifo_peek( L, fifo, count); // fifo ... 496 fifo_peek(L, fifo, count); // fifo ...
490 return (int) count; 497 return count;
491 } 498 }
492 // no fifo was ever registered for this key, or it is empty 499 // no fifo was ever registered for this key, or it is empty
493 return 0; 500 return 0;
494} 501}
495 502
503// ##################################################################################################
504
496// in: linda_ud [, key [, ...]] 505// in: linda_ud [, key [, ...]]
497int keepercall_count( lua_State* L) 506int keepercall_count(lua_State* L)
498{ 507{
499 push_table( L, 1); // ud keys fifos 508 push_table(L, 1); // ud keys fifos
500 switch( lua_gettop( L)) 509 switch (lua_gettop(L))
501 { 510 {
502 // no key is specified: return a table giving the count of all known keys 511 // no key is specified: return a table giving the count of all known keys
503 case 2: // ud fifos 512 case 2: // ud fifos
504 lua_newtable( L); // ud fifos out 513 lua_newtable(L); // ud fifos out
505 lua_replace( L, 1); // out fifos 514 lua_replace(L, 1); // out fifos
506 lua_pushnil( L); // out fifos nil 515 lua_pushnil(L); // out fifos nil
507 while( lua_next( L, 2)) // out fifos key fifo 516 while (lua_next(L, 2)) // out fifos key fifo
508 { 517 {
509 keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo 518 keeper_fifo* const fifo{ prepare_fifo_access(L, -1) }; // out fifos key fifo
510 lua_pop( L, 1); // out fifos key 519 lua_pop(L, 1); // out fifos key
511 lua_pushvalue( L, -1); // out fifos key key 520 lua_pushvalue(L, -1); // out fifos key key
512 lua_pushinteger( L, fifo->count); // out fifos key key count 521 lua_pushinteger(L, fifo->count); // out fifos key key count
513 lua_rawset( L, -5); // out fifos key 522 lua_rawset(L, -5); // out fifos key
514 } 523 }
515 lua_pop( L, 1); // out 524 lua_pop(L, 1); // out
516 break; 525 break;
517 526
518 // 1 key is specified: return its count 527 // 1 key is specified: return its count
519 case 3: // ud key fifos 528 case 3: // ud key fifos
520 { 529 lua_replace(L, 1); // fifos key
521 keeper_fifo* fifo; 530 lua_rawget(L, -2); // fifos fifo|nil
522 lua_replace( L, 1); // fifos key 531 if (lua_isnil(L, -1)) // the key is unknown
523 lua_rawget( L, -2); // fifos fifo|nil 532 { // fifos nil
524 if( lua_isnil( L, -1)) // the key is unknown 533 lua_remove(L, -2); // nil
525 { // fifos nil 534 }
526 lua_remove( L, -2); // nil 535 else // the key is known
527 } 536 { // fifos fifo
528 else // the key is known 537 keeper_fifo* const fifo{ prepare_fifo_access(L, -1) }; // fifos fifo
529 { // fifos fifo 538 lua_pushinteger(L, fifo->count); // fifos fifo count
530 fifo = prepare_fifo_access( L, -1); // fifos fifo 539 lua_replace(L, -3); // count fifo
531 lua_pushinteger( L, fifo->count); // fifos fifo count 540 lua_pop(L, 1); // count
532 lua_replace( L, -3); // count fifo
533 lua_pop( L, 1); // count
534 }
535 } 541 }
536 break; 542 break;
537 543
538 // a variable number of keys is specified: return a table of their counts 544 // a variable number of keys is specified: return a table of their counts
539 default: // ud keys fifos 545 default: // ud keys fifos
540 lua_newtable( L); // ud keys fifos out 546 lua_newtable(L); // ud keys fifos out
541 lua_replace( L, 1); // out keys fifos 547 lua_replace(L, 1); // out keys fifos
542 // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable 548 // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable
543 lua_insert( L, 2); // out fifos keys 549 lua_insert(L, 2); // out fifos keys
544 while( lua_gettop( L) > 2) 550 while (lua_gettop(L) > 2)
545 { 551 {
546 keeper_fifo* fifo; 552 lua_pushvalue(L, -1); // out fifos keys key
547 lua_pushvalue( L, -1); // out fifos keys key 553 lua_rawget(L, 2); // out fifos keys fifo|nil
548 lua_rawget( L, 2); // out fifos keys fifo|nil 554 keeper_fifo* const fifo{ prepare_fifo_access(L, -1) }; // out fifos keys fifo|nil
549 fifo = prepare_fifo_access( L, -1); // out fifos keys fifo|nil 555 lua_pop(L, 1); // out fifos keys
550 lua_pop( L, 1); // out fifos keys 556 if (fifo != nullptr) // the key is known
551 if( fifo != nullptr) // the key is known
552 { 557 {
553 lua_pushinteger( L, fifo->count); // out fifos keys count 558 lua_pushinteger(L, fifo->count); // out fifos keys count
554 lua_rawset( L, 1); // out fifos keys 559 lua_rawset(L, 1); // out fifos keys
555 } 560 }
556 else // the key is unknown 561 else // the key is unknown
557 { 562 {
558 lua_pop( L, 1); // out fifos keys 563 lua_pop(L, 1); // out fifos keys
559 } 564 }
560 } 565 }
561 lua_pop( L, 1); // out 566 lua_pop(L, 1); // out
562 } 567 }
563 ASSERT_L( lua_gettop( L) == 1); 568 ASSERT_L(lua_gettop(L) == 1);
564 return 1; 569 return 1;
565} 570}
566 571
@@ -580,24 +585,23 @@ int keepercall_count( lua_State* L)
580*/ 585*/
581 586
582// called as __gc for the keepers array userdata 587// called as __gc for the keepers array userdata
583void close_keepers( Universe* U) 588void close_keepers(Universe* U)
584{ 589{
585 if( U->keepers != nullptr) 590 if (U->keepers != nullptr)
586 { 591 {
587 int i;
588 int nbKeepers = U->keepers->nb_keepers; 592 int nbKeepers = U->keepers->nb_keepers;
589 // 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 593 // 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
590 // 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 594 // 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
591 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success 595 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success
592 // which is early-outed with a U->keepers->nbKeepers null-check 596 // which is early-outed with a U->keepers->nbKeepers null-check
593 U->keepers->nb_keepers = 0; 597 U->keepers->nb_keepers = 0;
594 for( i = 0; i < nbKeepers; ++ i) 598 for (int i = 0; i < nbKeepers; ++i)
595 { 599 {
596 lua_State* K = U->keepers->keeper_array[i].L; 600 lua_State* K = U->keepers->keeper_array[i].L;
597 U->keepers->keeper_array[i].L = nullptr; 601 U->keepers->keeper_array[i].L = nullptr;
598 if( K != nullptr) 602 if (K != nullptr)
599 { 603 {
600 lua_close( K); 604 lua_close(K);
601 } 605 }
602 else 606 else
603 { 607 {
@@ -605,19 +609,21 @@ void close_keepers( Universe* U)
605 nbKeepers = i; 609 nbKeepers = i;
606 } 610 }
607 } 611 }
608 for( i = 0; i < nbKeepers; ++ i) 612 for (int i = 0; i < nbKeepers; ++i)
609 { 613 {
610 MUTEX_FREE( &U->keepers->keeper_array[i].keeper_cs); 614 MUTEX_FREE(&U->keepers->keeper_array[i].keeper_cs);
611 } 615 }
612 // free the keeper bookkeeping structure 616 // free the keeper bookkeeping structure
613 { 617 {
614 AllocatorDefinition* const allocD = &U->internal_allocator; 618 AllocatorDefinition* const allocD = &U->internal_allocator;
615 (void) allocD->allocF( allocD->allocUD, U->keepers, sizeof( Keepers) + (nbKeepers - 1) * sizeof( Keeper), 0); 619 std::ignore = allocD->allocF(allocD->allocUD, U->keepers, sizeof(Keepers) + (nbKeepers - 1) * sizeof(Keeper), 0);
616 U->keepers = nullptr; 620 U->keepers = nullptr;
617 } 621 }
618 } 622 }
619} 623}
620 624
625// ##################################################################################################
626
621/* 627/*
622 * Initialize keeper states 628 * Initialize keeper states
623 * 629 *
@@ -629,42 +635,39 @@ void close_keepers( Universe* U)
629 * function never fails. 635 * function never fails.
630 * settings table is at position 1 on the stack 636 * settings table is at position 1 on the stack
631 */ 637 */
632void init_keepers( Universe* U, lua_State* L) 638void init_keepers(Universe* U, lua_State* L)
633{ 639{
634 int i; 640 STACK_CHECK(L, 0); // L K
635 int nb_keepers; 641 lua_getfield(L, 1, "nb_keepers"); // nb_keepers
636 642 int nb_keepers{ static_cast<int>(lua_tointeger(L, -1)) };
637 STACK_CHECK( L, 0); // L K 643 lua_pop(L, 1); //
638 lua_getfield( L, 1, "nb_keepers"); // nb_keepers 644 if (nb_keepers < 1)
639 nb_keepers = (int) lua_tointeger( L, -1);
640 lua_pop( L, 1); //
641 if( nb_keepers < 1)
642 { 645 {
643 (void) luaL_error( L, "Bad number of keepers (%d)", nb_keepers); 646 (void) luaL_error(L, "Bad number of keepers (%d)", nb_keepers);
644 } 647 }
645 648
646 // Keepers contains an array of 1 Keeper, adjust for the actual number of keeper states 649 // Keepers contains an array of 1 Keeper, adjust for the actual number of keeper states
647 { 650 {
648 size_t const bytes = sizeof( Keepers) + (nb_keepers - 1) * sizeof( Keeper); 651 size_t const bytes = sizeof(Keepers) + (nb_keepers - 1) * sizeof(Keeper);
649 { 652 {
650 AllocatorDefinition* const allocD = &U->internal_allocator; 653 AllocatorDefinition* const allocD = &U->internal_allocator;
651 U->keepers = (Keepers*) allocD->allocF( allocD->allocUD, nullptr, 0, bytes); 654 U->keepers = (Keepers*) allocD->allocF(allocD->allocUD, nullptr, 0, bytes);
652 } 655 }
653 if( U->keepers == nullptr) 656 if (U->keepers == nullptr)
654 { 657 {
655 (void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory"); 658 (void) luaL_error(L, "init_keepers() failed while creating keeper array; out of memory");
656 return; 659 return;
657 } 660 }
658 memset( U->keepers, 0, bytes); 661 memset(U->keepers, 0, bytes);
659 U->keepers->nb_keepers = nb_keepers; 662 U->keepers->nb_keepers = nb_keepers;
660 } 663 }
661 for( i = 0; i < nb_keepers; ++ i) // keepersUD 664 for (int i = 0; i < nb_keepers; ++i) // keepersUD
662 { 665 {
663 // note that we will leak K if we raise an error later 666 // note that we will leak K if we raise an error later
664 lua_State* K = create_state( U, L); 667 lua_State* const K{ create_state(U, L) };
665 if( K == nullptr) 668 if (K == nullptr)
666 { 669 {
667 (void) luaL_error( L, "init_keepers() failed while creating keeper states; out of memory"); 670 std::ignore = luaL_error(L, "init_keepers() failed while creating keeper states; out of memory");
668 return; 671 return;
669 } 672 }
670 673
@@ -672,64 +675,68 @@ void init_keepers( Universe* U, lua_State* L)
672 // we can trigger a GC from inside keeper_call(), where a keeper is acquired 675 // we can trigger a GC from inside keeper_call(), where a keeper is acquired
673 // from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread. 676 // from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread.
674 // therefore, we need a recursive mutex. 677 // therefore, we need a recursive mutex.
675 MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); 678 MUTEX_RECURSIVE_INIT(&U->keepers->keeper_array[i].keeper_cs);
676 679
677 STACK_CHECK( K, 0); 680 STACK_CHECK(K, 0);
678 681
679 // copy the universe pointer in the keeper itself 682 // copy the universe pointer in the keeper itself
680 universe_store( K, U); 683 universe_store(K, U);
681 STACK_MID( K, 0); 684 STACK_MID(K, 0);
682 685
683 // make sure 'package' is initialized in keeper states, so that we have require() 686 // make sure 'package' is initialized in keeper states, so that we have require()
684 // this because this is needed when transferring deep userdata object 687 // this because this is needed when transferring deep userdata object
685 luaL_requiref( K, "package", luaopen_package, 1); // package 688 luaL_requiref(K, "package", luaopen_package, 1); // package
686 lua_pop( K, 1); // 689 lua_pop(K, 1); //
687 STACK_MID( K, 0); 690 STACK_MID(K, 0);
688 serialize_require( DEBUGSPEW_PARAM_COMMA( U) K); 691 serialize_require(DEBUGSPEW_PARAM_COMMA(U) K);
689 STACK_MID( K, 0); 692 STACK_MID(K, 0);
690 693
691 // copy package.path and package.cpath from the source state 694 // copy package.path and package.cpath from the source state
692 lua_getglobal( L, "package"); // "..." keepersUD package 695 lua_getglobal(L, "package"); // "..." keepersUD package
693 if( !lua_isnil( L, -1)) 696 if (!lua_isnil(L, -1))
694 { 697 {
695 // when copying with mode eLM_ToKeeper, error message is pushed at the top of the stack, not raised immediately 698 // when copying with mode eLM_ToKeeper, error message is pushed at the top of the stack, not raised immediately
696 if( luaG_inter_copy_package( U, L, K, -1, eLM_ToKeeper)) 699 if (luaG_inter_copy_package(U, L, K, -1, eLM_ToKeeper))
697 { 700 {
698 // if something went wrong, the error message is at the top of the stack 701 // if something went wrong, the error message is at the top of the stack
699 lua_remove( L, -2); // error_msg 702 lua_remove(L, -2); // error_msg
700 (void) lua_error( L); 703 (void) lua_error(L);
701 return; 704 return;
702 } 705 }
703 } 706 }
704 lua_pop( L, 1); // 707 lua_pop(L, 1); //
705 STACK_MID( L, 0); 708 STACK_MID(L, 0);
706 709
707 // attempt to call on_state_create(), if we have one and it is a C function 710 // attempt to call on_state_create(), if we have one and it is a C function
708 // (only support a C function because we can't transfer executable Lua code in keepers) 711 // (only support a C function because we can't transfer executable Lua code in keepers)
709 // will raise an error in L in case of problem 712 // will raise an error in L in case of problem
710 call_on_state_create( U, K, L, eLM_ToKeeper); 713 call_on_state_create(U, K, L, eLM_ToKeeper);
711 714
712 // to see VM name in Decoda debugger 715 // to see VM name in Decoda debugger
713 lua_pushfstring( K, "Keeper #%d", i + 1); // "Keeper #n" 716 lua_pushfstring(K, "Keeper #%d", i + 1); // "Keeper #n"
714 lua_setglobal( K, "decoda_name"); // 717 lua_setglobal(K, "decoda_name"); //
715 // create the fifos table in the keeper state 718 // create the fifos table in the keeper state
716 FIFOS_KEY.set_registry(K, [](lua_State* L) { lua_newtable(L); } ); 719 FIFOS_KEY.set_registry(K, [](lua_State* L) { lua_newtable(L); });
717 STACK_END( K, 0); 720 STACK_END(K, 0);
718 } 721 }
719 STACK_END( L, 0); 722 STACK_END(L, 0);
720} 723}
721 724
725// ##################################################################################################
726
722// should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call) 727// should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call)
723Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_) 728Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_)
724{ 729{
725 int const nbKeepers = keepers_->nb_keepers; 730 int const nbKeepers{ keepers_->nb_keepers };
726 unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); 731 unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers);
727 return &keepers_->keeper_array[i]; 732 return &keepers_->keeper_array[i];
728} 733}
729 734
730Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) 735// ##################################################################################################
736
737Keeper* keeper_acquire(Keepers* keepers_, ptrdiff_t magic_)
731{ 738{
732 int const nbKeepers = keepers_->nb_keepers; 739 int const nbKeepers{ keepers_->nb_keepers };
733 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) 740 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers)
734 if( nbKeepers == 0) 741 if( nbKeepers == 0)
735 { 742 {
@@ -753,36 +760,45 @@ Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_)
753 } 760 }
754} 761}
755 762
756void keeper_release( Keeper* K) 763// ##################################################################################################
764
765void keeper_release(Keeper* K)
757{ 766{
758 //-- K->count; 767 //-- K->count;
759 if( K) MUTEX_UNLOCK( &K->keeper_cs); 768 if (K)
769 {
770 MUTEX_UNLOCK(&K->keeper_cs);
771 }
760} 772}
761 773
762void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) 774// ##################################################################################################
775
776void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode_)
763{ 777{
764 int i, n = lua_gettop( L); 778 int const n{ lua_gettop(L) };
765 for( i = val_i_; i <= n; ++ i) 779 for (int i = val_i_; i <= n; ++i)
766 { 780 {
767 if( mode_ == eLM_ToKeeper) 781 if (mode_ == eLM_ToKeeper)
768 { 782 {
769 if( lua_isnil( L, i)) 783 if (lua_isnil(L, i))
770 { 784 {
771 NIL_SENTINEL.push(L); 785 NIL_SENTINEL.push(L);
772 lua_replace( L, i); 786 lua_replace(L, i);
773 } 787 }
774 } 788 }
775 else 789 else
776 { 790 {
777 if (NIL_SENTINEL.equals(L, i)) 791 if (NIL_SENTINEL.equals(L, i))
778 { 792 {
779 lua_pushnil( L); 793 lua_pushnil(L);
780 lua_replace( L, i); 794 lua_replace(L, i);
781 } 795 }
782 } 796 }
783 } 797 }
784} 798}
785 799
800// ##################################################################################################
801
786/* 802/*
787* Call a function ('func_name') in the keeper state, and pass on the returned 803* Call a function ('func_name') in the keeper state, and pass on the returned
788* values to 'L'. 804* values to 'L'.
@@ -794,31 +810,31 @@ void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mod
794*/ 810*/
795int keeper_call(Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, int starting_index) 811int keeper_call(Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, int starting_index)
796{ 812{
797 int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; 813 int const args{ starting_index ? (lua_gettop(L) - starting_index + 1) : 0 };
798 int const Ktos = lua_gettop( K); 814 int const Ktos{ lua_gettop(K) };
799 int retvals = -1; 815 int retvals = -1;
800 816
801 STACK_GROW( K, 2); 817 STACK_GROW(K, 2);
802 818
803 PUSH_KEEPER_FUNC( K, func_); 819 PUSH_KEEPER_FUNC(K, func_);
804 820
805 lua_pushlightuserdata( K, linda); 821 lua_pushlightuserdata(K, linda);
806 822
807 if( (args == 0) || luaG_inter_copy( U, L, K, args, eLM_ToKeeper) == 0) // L->K 823 if ((args == 0) || luaG_inter_copy(U, L, K, args, eLM_ToKeeper) == 0) // L->K
808 { 824 {
809 lua_call( K, 1 + args, LUA_MULTRET); 825 lua_call(K, 1 + args, LUA_MULTRET);
810 826
811 retvals = lua_gettop( K) - Ktos; 827 retvals = lua_gettop(K) - Ktos;
812 // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired 828 // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired
813 // this may interrupt a lane, causing the destruction of the underlying OS thread 829 // this may interrupt a lane, causing the destruction of the underlying OS thread
814 // after this, another lane making use of this keeper can get an error code from the mutex-locking function 830 // after this, another lane making use of this keeper can get an error code from the mutex-locking function
815 // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) 831 // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread)
816 if( (retvals > 0) && luaG_inter_move( U, K, L, retvals, eLM_FromKeeper) != 0) // K->L 832 if ((retvals > 0) && luaG_inter_move(U, K, L, retvals, eLM_FromKeeper) != 0) // K->L
817 { 833 {
818 retvals = -1; 834 retvals = -1;
819 } 835 }
820 } 836 }
821 // whatever happens, restore the stack to where it was at the origin 837 // whatever happens, restore the stack to where it was at the origin
822 lua_settop( K, Ktos); 838 lua_settop(K, Ktos);
823 return retvals; 839 return retvals;
824} 840}
diff --git a/src/keeper.h b/src/keeper.h
index ce9742a..5f52fa0 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -19,7 +19,7 @@ struct Keeper
19{ 19{
20 MUTEX_T keeper_cs; 20 MUTEX_T keeper_cs;
21 lua_State* L; 21 lua_State* L;
22 //int count; 22 // int count;
23}; 23};
24 24
25struct Keepers 25struct Keepers
@@ -28,30 +28,30 @@ struct Keepers
28 Keeper keeper_array[1]; 28 Keeper keeper_array[1];
29}; 29};
30 30
31void init_keepers( Universe* U, lua_State* L); 31static constexpr ptrdiff_t KEEPER_MAGIC_SHIFT{ 3 };
32void close_keepers( Universe* U);
33
34Keeper* which_keeper( Keepers* keepers_, ptrdiff_t magic_);
35Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_);
36#define KEEPER_MAGIC_SHIFT 3
37void keeper_release( Keeper* K);
38void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_);
39int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_);
40
41// crc64/we of string "NIL_SENTINEL" generated at http://www.nitrxgen.net/hashgen/ 32// crc64/we of string "NIL_SENTINEL" generated at http://www.nitrxgen.net/hashgen/
42static constexpr UniqueKey NIL_SENTINEL{ 0x7eaafa003a1d11a1ull }; 33static constexpr UniqueKey NIL_SENTINEL{ 0x7eaafa003a1d11a1ull };
43 34
35void init_keepers(Universe* U, lua_State* L);
36void close_keepers(Universe* U);
37
38Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_);
39Keeper* keeper_acquire(Keepers* keepers_, ptrdiff_t magic_);
40void keeper_release(Keeper* K);
41void keeper_toggle_nil_sentinels(lua_State* L, int val_i_, LookupMode const mode_);
42int keeper_push_linda_storage(Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_);
43
44using keeper_api_t = lua_CFunction; 44using keeper_api_t = lua_CFunction;
45#define KEEPER_API( _op) keepercall_ ## _op 45#define KEEPER_API(_op) keepercall_##_op
46#define PUSH_KEEPER_FUNC lua_pushcfunction 46#define PUSH_KEEPER_FUNC lua_pushcfunction
47// lua_Cfunctions to run inside a keeper state (formerly implemented in Lua) 47// lua_Cfunctions to run inside a keeper state
48int keepercall_clear( lua_State* L); 48int keepercall_clear(lua_State* L);
49int keepercall_send( lua_State* L); 49int keepercall_send(lua_State* L);
50int keepercall_receive( lua_State* L); 50int keepercall_receive(lua_State* L);
51int keepercall_receive_batched( lua_State* L); 51int keepercall_receive_batched(lua_State* L);
52int keepercall_limit( lua_State* L); 52int keepercall_limit(lua_State* L);
53int keepercall_get( lua_State* L); 53int keepercall_get(lua_State* L);
54int keepercall_set( lua_State* L); 54int keepercall_set(lua_State* L);
55int keepercall_count( lua_State* L); 55int keepercall_count(lua_State* L);
56 56
57int keeper_call(Universe* U, lua_State* K, keeper_api_t _func, lua_State* L, void* linda, int starting_index); 57int keeper_call(Universe* U, lua_State* K, keeper_api_t _func, lua_State* L, void* linda, int starting_index);
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 1589240..38dd92c 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -2076,7 +2076,7 @@ static void EnableCrashingOnCrashes( void)
2076 while( !s_ecoc_go_ahead) { Sleep(1); } // changes threads 2076 while( !s_ecoc_go_ahead) { Sleep(1); } // changes threads
2077 } 2077 }
2078} 2078}
2079#endif // PLATFORM_WIN32 2079#endif // PLATFORM_WIN32 && !defined NDEBUG
2080 2080
2081LANES_API int luaopen_lanes_core( lua_State* L) 2081LANES_API int luaopen_lanes_core( lua_State* L)
2082{ 2082{
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h
index 67213bc..9982693 100644
--- a/src/macros_and_utils.h
+++ b/src/macros_and_utils.h
@@ -5,6 +5,7 @@ extern "C" {
5#endif // __cplusplus 5#endif // __cplusplus
6#include "lua.h" 6#include "lua.h"
7#include "lualib.h" 7#include "lualib.h"
8#include "lauxlib.h"
8#ifdef __cplusplus 9#ifdef __cplusplus
9} 10}
10#endif // __cplusplus 11#endif // __cplusplus
@@ -78,6 +79,10 @@ extern char const* debugspew_indent;
78 79
79#define ASSERT_L(c) _ASSERT_L(L,c) 80#define ASSERT_L(c) _ASSERT_L(L,c)
80 81
81#define STACK_GROW( L, n) do { if (!lua_checkstack(L,(int)(n))) luaL_error( L, "Cannot grow stack!" ); } while( 0) 82inline void STACK_GROW(lua_State* L, int n_)
83{
84 if (!lua_checkstack(L, n_))
85 luaL_error(L, "Cannot grow stack!");
86}
82 87
83#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L) 88#define LUAG_FUNC( func_name) int LG_##func_name( lua_State* L)
diff --git a/src/platform.h b/src/platform.h
index ce621d9..b10f0ad 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -6,6 +6,7 @@
6 #define PLATFORM_XBOX 6 #define PLATFORM_XBOX
7#elif (defined _WIN32) 7#elif (defined _WIN32)
8 #define PLATFORM_WIN32 8 #define PLATFORM_WIN32
9 #define NOMINMAX
9#elif (defined __linux__) 10#elif (defined __linux__)
10 #define PLATFORM_LINUX 11 #define PLATFORM_LINUX
11#elif (defined __APPLE__) && (defined __MACH__) 12#elif (defined __APPLE__) && (defined __MACH__)
diff --git a/tests/fifo.lua b/tests/fifo.lua
index bef60d5..8bd1fc2 100644
--- a/tests/fifo.lua
+++ b/tests/fifo.lua
@@ -6,24 +6,27 @@
6 6
7local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true} 7local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true}
8 8
9local linda = lanes.linda( "atom") 9local atomic_linda = lanes.linda( "atom")
10local atomic_inc= lanes.genatomic( linda, "FIFO_n") 10local atomic_inc= lanes.genatomic( atomic_linda, "FIFO_n")
11
12local fifo_linda = lanes.linda( "fifo")
11 13
12assert( atomic_inc()==1) 14assert( atomic_inc()==1)
13assert( atomic_inc()==2) 15assert( atomic_inc()==2)
14 16
15local function FIFO() 17local function FIFO()
16 local my_channel= "FIFO"..atomic_inc() 18 local my_channel= "FIFO_"..atomic_inc()
17 19
18 return { 20 return {
19 -- Giving explicit 'nil' timeout allows numbers to be used as 'my_channel' 21 -- Giving explicit 'nil' timeout allows numbers to be used as 'my_channel'
20 -- 22 --
21 send = function(self, ...) 23 send = function(self, ...)
22 linda:send( nil, my_channel, ...) 24 fifo_linda:send( nil, my_channel, ...)
23 end, 25 end,
24 receive = function(self, timeout) 26 receive = function(self, timeout)
25 return linda:receive( timeout, my_channel) 27 return fifo_linda:receive( timeout, my_channel)
26 end 28 end,
29 channel = my_channel
27 } 30 }
28end 31end
29 32
@@ -36,11 +39,31 @@ A:send( 1,2,3,4,5)
36print "Sending to B.." 39print "Sending to B.."
37B:send( 'a','b','c') 40B:send( 'a','b','c')
38 41
42print "Dumping linda stats.. [1]" -- count everything
43for key,count in pairs(fifo_linda:count()) do
44 print("channel " .. key .. " contains " .. count .. " entries.")
45 -- print(i, key_count[1], key_count[2])
46end
47print "Dumping linda stats.. [2]" -- query count for known channels one at a time
48print("channel " .. A.channel .. " contains " .. fifo_linda:count(A.channel) .. " entries.")
49print("channel " .. B.channel .. " contains " .. fifo_linda:count(B.channel) .. " entries.")
50print "Dumping linda stats.. [3]" -- query counts for a predefined list of keys
51for key,count in pairs(fifo_linda:count(A.channel, B.channel)) do
52 print("channel " .. key .. " contains " .. count .. " entries.")
53 -- print(i, key_count[1], key_count[2])
54end
55
39print "Reading A.." 56print "Reading A.."
40print( A:receive( 1.0)) 57print( A:receive( 1.0))
58print( A:receive( 1.0))
59print( A:receive( 1.0))
60print( A:receive( 1.0))
61print( A:receive( 1.0))
41 62
42print "Reading B.." 63print "Reading B.."
43print( B:receive( 2.0)) 64print( B:receive( 2.0))
65print( B:receive( 2.0))
66print( B:receive( 2.0))
44 67
45-- Note: A and B can be passed between threads, or used as upvalues 68-- Note: A and B can be passed between threads, or used as upvalues
46-- by multiple threads (other parts will be copied but the 'linda' 69-- by multiple threads (other parts will be copied but the 'linda'