diff options
Diffstat (limited to 'src/keeper.c')
-rw-r--r-- | src/keeper.c | 1208 |
1 files changed, 604 insertions, 604 deletions
diff --git a/src/keeper.c b/src/keeper.c index c777866..eea017f 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -61,9 +61,9 @@ | |||
61 | 61 | ||
62 | typedef struct | 62 | typedef struct |
63 | { | 63 | { |
64 | lua_Integer first; | 64 | lua_Integer first; |
65 | lua_Integer count; | 65 | lua_Integer count; |
66 | lua_Integer limit; | 66 | lua_Integer limit; |
67 | } keeper_fifo; | 67 | } keeper_fifo; |
68 | 68 | ||
69 | static int const CONTENTS_TABLE = 1; | 69 | static int const CONTENTS_TABLE = 1; |
@@ -71,47 +71,47 @@ static int const CONTENTS_TABLE = 1; | |||
71 | // replaces the fifo ud by its uservalue on the stack | 71 | // replaces the fifo ud by its uservalue on the stack |
72 | static keeper_fifo* prepare_fifo_access( lua_State* L, int idx_) | 72 | static keeper_fifo* prepare_fifo_access( lua_State* L, int idx_) |
73 | { | 73 | { |
74 | keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx_); | 74 | keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx_); |
75 | if( fifo != NULL) | 75 | if( fifo != NULL) |
76 | { | 76 | { |
77 | idx_ = lua_absindex( L, idx_); | 77 | idx_ = lua_absindex( L, idx_); |
78 | STACK_GROW( L, 1); | 78 | 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 | 79 | // 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); | 80 | lua_getiuservalue( L, idx_, CONTENTS_TABLE); |
81 | lua_replace( L, idx_); | 81 | lua_replace( L, idx_); |
82 | } | 82 | } |
83 | return fifo; | 83 | return fifo; |
84 | } | 84 | } |
85 | 85 | ||
86 | // in: nothing | 86 | // in: nothing |
87 | // out: { first = 1, count = 0, limit = -1} | 87 | // out: { first = 1, count = 0, limit = -1} |
88 | static void fifo_new( lua_State* L) | 88 | static void fifo_new( lua_State* L) |
89 | { | 89 | { |
90 | keeper_fifo* fifo; | 90 | keeper_fifo* fifo; |
91 | STACK_GROW( L, 2); | 91 | STACK_GROW( L, 2); |
92 | // a fifo full userdata has one uservalue, the table that holds the actual fifo contents | 92 | // 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); | 93 | fifo = (keeper_fifo*)lua_newuserdatauv( L, sizeof( keeper_fifo), 1); |
94 | fifo->first = 1; | 94 | fifo->first = 1; |
95 | fifo->count = 0; | 95 | fifo->count = 0; |
96 | fifo->limit = -1; | 96 | fifo->limit = -1; |
97 | lua_newtable( L); | 97 | lua_newtable( L); |
98 | lua_setiuservalue( L, -2, CONTENTS_TABLE); | 98 | lua_setiuservalue( L, -2, CONTENTS_TABLE); |
99 | } | 99 | } |
100 | 100 | ||
101 | // in: expect fifo ... on top of the stack | 101 | // in: expect fifo ... on top of the stack |
102 | // out: nothing, removes all pushed values from the stack | 102 | // out: nothing, removes all pushed values from the stack |
103 | static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | 103 | static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) |
104 | { | 104 | { |
105 | int const idx = lua_gettop( L) - (int) count_; | 105 | int const idx = lua_gettop( L) - (int) count_; |
106 | lua_Integer start = fifo_->first + fifo_->count - 1; | 106 | lua_Integer start = fifo_->first + fifo_->count - 1; |
107 | lua_Integer i; | 107 | lua_Integer i; |
108 | // pop all additional arguments, storing them in the fifo | 108 | // pop all additional arguments, storing them in the fifo |
109 | for( i = count_; i >= 1; -- i) | 109 | for( i = count_; i >= 1; -- i) |
110 | { | 110 | { |
111 | // store in the fifo the value at the top of the stack at the specified index, popping it from the stack | 111 | // 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)); | 112 | lua_rawseti( L, idx, (int)(start + i)); |
113 | } | 113 | } |
114 | fifo_->count += count_; | 114 | fifo_->count += count_; |
115 | } | 115 | } |
116 | 116 | ||
117 | // in: fifo | 117 | // in: fifo |
@@ -121,46 +121,46 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
121 | // function assumes that there is enough data in the fifo to satisfy the request | 121 | // function assumes that there is enough data in the fifo to satisfy the request |
122 | static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | 122 | static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) |
123 | { | 123 | { |
124 | lua_Integer i; | 124 | lua_Integer i; |
125 | STACK_GROW( L, count_); | 125 | STACK_GROW( L, count_); |
126 | for( i = 0; i < count_; ++ i) | 126 | for( i = 0; i < count_; ++ i) |
127 | { | 127 | { |
128 | lua_rawgeti( L, 1, (int)( fifo_->first + i)); | 128 | lua_rawgeti( L, 1, (int)( fifo_->first + i)); |
129 | } | 129 | } |
130 | } | 130 | } |
131 | 131 | ||
132 | // in: fifo | 132 | // 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) | 133 | // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) |
134 | static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | 134 | static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) |
135 | { | 135 | { |
136 | int const fifo_idx = lua_gettop( L); // ... fifo | 136 | int const fifo_idx = lua_gettop( L); // ... fifo |
137 | int i; | 137 | int i; |
138 | // each iteration pushes a value on the stack! | 138 | // each iteration pushes a value on the stack! |
139 | STACK_GROW( L, count_ + 2); | 139 | STACK_GROW( L, count_ + 2); |
140 | // skip first item, we will push it last | 140 | // skip first item, we will push it last |
141 | for( i = 1; i < count_; ++ i) | 141 | for( i = 1; i < count_; ++ i) |
142 | { | 142 | { |
143 | int const at = (int)( fifo_->first + i); | 143 | int const at = (int)( fifo_->first + i); |
144 | // push item on the stack | 144 | // push item on the stack |
145 | lua_rawgeti( L, fifo_idx, at); // ... fifo val | 145 | lua_rawgeti( L, fifo_idx, at); // ... fifo val |
146 | // remove item from the fifo | 146 | // remove item from the fifo |
147 | lua_pushnil( L); // ... fifo val nil | 147 | lua_pushnil( L); // ... fifo val nil |
148 | lua_rawseti( L, fifo_idx, at); // ... fifo val | 148 | lua_rawseti( L, fifo_idx, at); // ... fifo val |
149 | } | 149 | } |
150 | // now process first item | 150 | // now process first item |
151 | { | 151 | { |
152 | int const at = (int)( fifo_->first); | 152 | int const at = (int)( fifo_->first); |
153 | lua_rawgeti( L, fifo_idx, at); // ... fifo vals val | 153 | lua_rawgeti( L, fifo_idx, at); // ... fifo vals val |
154 | lua_pushnil( L); // ... fifo vals val nil | 154 | lua_pushnil( L); // ... fifo vals val nil |
155 | lua_rawseti( L, fifo_idx, at); // ... fifo vals val | 155 | lua_rawseti( L, fifo_idx, at); // ... fifo vals val |
156 | lua_replace( L, fifo_idx); // ... vals | 156 | lua_replace( L, fifo_idx); // ... vals |
157 | } | 157 | } |
158 | { | 158 | { |
159 | // avoid ever-growing indexes by resetting each time we detect the fifo is empty | 159 | // avoid ever-growing indexes by resetting each time we detect the fifo is empty |
160 | lua_Integer const new_count = fifo_->count - count_; | 160 | lua_Integer const new_count = fifo_->count - count_; |
161 | fifo_->first = (new_count == 0) ? 1 : (fifo_->first + count_); | 161 | fifo_->first = (new_count == 0) ? 1 : (fifo_->first + count_); |
162 | fifo_->count = new_count; | 162 | fifo_->count = new_count; |
163 | } | 163 | } |
164 | } | 164 | } |
165 | 165 | ||
166 | // in: linda_ud expected at *absolute* stack slot idx | 166 | // in: linda_ud expected at *absolute* stack slot idx |
@@ -169,87 +169,87 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
169 | static DECLARE_CONST_UNIQUE_KEY( FIFOS_KEY, 0xdce50bbc351cd465); | 169 | static DECLARE_CONST_UNIQUE_KEY( FIFOS_KEY, 0xdce50bbc351cd465); |
170 | static void push_table( lua_State* L, int idx_) | 170 | static 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 | REGISTRY_GET( L, FIFOS_KEY); // ud fifos | 175 | REGISTRY_GET( L, FIFOS_KEY); // 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 | ||
192 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) | 192 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) |
193 | { | 193 | { |
194 | Keeper* const K = which_keeper( U->keepers, magic_); | 194 | Keeper* const K = which_keeper( U->keepers, magic_); |
195 | lua_State* const KL = K ? K->L : NULL; | 195 | lua_State* const KL = K ? K->L : NULL; |
196 | if( KL == NULL) return 0; | 196 | if( KL == NULL) return 0; |
197 | STACK_GROW( KL, 4); | 197 | STACK_GROW( KL, 4); |
198 | STACK_CHECK( KL, 0); | 198 | STACK_CHECK( KL, 0); |
199 | REGISTRY_GET( KL, FIFOS_KEY); // fifos | 199 | REGISTRY_GET( KL, FIFOS_KEY); // fifos |
200 | lua_pushlightuserdata( KL, ptr_); // fifos ud | 200 | lua_pushlightuserdata( KL, ptr_); // fifos ud |
201 | lua_rawget( KL, -2); // fifos storage | 201 | lua_rawget( KL, -2); // fifos storage |
202 | lua_remove( KL, -2); // storage | 202 | lua_remove( KL, -2); // storage |
203 | if( !lua_istable( KL, -1)) | 203 | if( !lua_istable( KL, -1)) |
204 | { | 204 | { |
205 | lua_pop( KL, 1); // | 205 | lua_pop( KL, 1); // |
206 | STACK_MID( KL, 0); | 206 | STACK_MID( KL, 0); |
207 | return 0; | 207 | return 0; |
208 | } | 208 | } |
209 | // move data from keeper to destination state KEEPER MAIN | 209 | // move data from keeper to destination state KEEPER MAIN |
210 | lua_pushnil( KL); // storage nil | 210 | lua_pushnil( KL); // storage nil |
211 | STACK_GROW( L, 5); | 211 | STACK_GROW( L, 5); |
212 | STACK_CHECK( L, 0); | 212 | STACK_CHECK( L, 0); |
213 | lua_newtable( L); // out | 213 | lua_newtable( L); // out |
214 | while( lua_next( KL, -2)) // storage key fifo | 214 | while( lua_next( KL, -2)) // storage key fifo |
215 | { | 215 | { |
216 | keeper_fifo* fifo = prepare_fifo_access( KL, -1); // storage key fifo | 216 | keeper_fifo* fifo = prepare_fifo_access( KL, -1); // storage key fifo |
217 | lua_pushvalue( KL, -2); // storage key fifo key | 217 | lua_pushvalue( KL, -2); // storage key fifo key |
218 | luaG_inter_move( U, KL, L, 1, eLM_FromKeeper); // storage key fifo // out key | 218 | luaG_inter_move( U, KL, L, 1, eLM_FromKeeper); // storage key fifo // out key |
219 | STACK_MID( L, 2); | 219 | STACK_MID( L, 2); |
220 | lua_newtable( L); // out key keyout | 220 | lua_newtable( L); // out key keyout |
221 | luaG_inter_move( U, KL, L, 1, eLM_FromKeeper); // storage key // out key keyout fifo | 221 | 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 | 222 | lua_pushinteger( L, fifo->first); // out key keyout fifo first |
223 | STACK_MID( L, 5); | 223 | STACK_MID( L, 5); |
224 | lua_setfield( L, -3, "first"); // out key keyout fifo | 224 | lua_setfield( L, -3, "first"); // out key keyout fifo |
225 | lua_pushinteger( L, fifo->count); // out key keyout fifo count | 225 | lua_pushinteger( L, fifo->count); // out key keyout fifo count |
226 | STACK_MID( L, 5); | 226 | STACK_MID( L, 5); |
227 | lua_setfield( L, -3, "count"); // out key keyout fifo | 227 | lua_setfield( L, -3, "count"); // out key keyout fifo |
228 | lua_pushinteger( L, fifo->limit); // out key keyout fifo limit | 228 | lua_pushinteger( L, fifo->limit); // out key keyout fifo limit |
229 | STACK_MID( L, 5); | 229 | STACK_MID( L, 5); |
230 | lua_setfield( L, -3, "limit"); // out key keyout fifo | 230 | lua_setfield( L, -3, "limit"); // out key keyout fifo |
231 | lua_setfield( L, -2, "fifo"); // out key keyout | 231 | lua_setfield( L, -2, "fifo"); // out key keyout |
232 | lua_rawset( L, -3); // out | 232 | lua_rawset( L, -3); // out |
233 | STACK_MID( L, 1); | 233 | STACK_MID( L, 1); |
234 | } | 234 | } |
235 | STACK_END( L, 1); | 235 | STACK_END( L, 1); |
236 | lua_pop( KL, 1); // | 236 | lua_pop( KL, 1); // |
237 | STACK_END( KL, 0); | 237 | STACK_END( KL, 0); |
238 | return 1; | 238 | return 1; |
239 | } | 239 | } |
240 | 240 | ||
241 | // in: linda_ud | 241 | // in: linda_ud |
242 | int keepercall_clear( lua_State* L) | 242 | int keepercall_clear( lua_State* L) |
243 | { | 243 | { |
244 | STACK_GROW( L, 3); | 244 | STACK_GROW( L, 3); |
245 | STACK_CHECK( L, 0); | 245 | STACK_CHECK( L, 0); |
246 | REGISTRY_GET( L, FIFOS_KEY); // ud fifos | 246 | REGISTRY_GET( L, FIFOS_KEY); // ud fifos |
247 | lua_pushvalue( L, 1); // ud fifos ud | 247 | lua_pushvalue( L, 1); // ud fifos ud |
248 | lua_pushnil( L); // ud fifos ud nil | 248 | lua_pushnil( L); // ud fifos ud nil |
249 | lua_rawset( L, -3); // ud fifos | 249 | lua_rawset( L, -3); // ud fifos |
250 | lua_pop( L, 1); // ud | 250 | lua_pop( L, 1); // ud |
251 | STACK_END( L, 0); | 251 | STACK_END( L, 0); |
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | 254 | ||
255 | 255 | ||
@@ -257,311 +257,311 @@ int keepercall_clear( lua_State* L) | |||
257 | // out: true|false | 257 | // out: true|false |
258 | int keepercall_send( lua_State* L) | 258 | int keepercall_send( lua_State* L) |
259 | { | 259 | { |
260 | keeper_fifo* fifo; | 260 | keeper_fifo* fifo; |
261 | int n = lua_gettop( L) - 2; | 261 | int n = lua_gettop( L) - 2; |
262 | 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 | 263 | // 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 | 264 | lua_pushvalue( L, 2); // ud key ... fifos key |
265 | lua_rawget( L, -2); // ud key ... fifos fifo | 265 | lua_rawget( L, -2); // ud key ... fifos fifo |
266 | if( lua_isnil( L, -1)) | 266 | if( lua_isnil( L, -1)) |
267 | { | 267 | { |
268 | lua_pop( L, 1); // ud key ... fifos | 268 | lua_pop( L, 1); // ud key ... fifos |
269 | fifo_new( L); // ud key ... fifos fifo | 269 | fifo_new( L); // ud key ... fifos fifo |
270 | lua_pushvalue( L, 2); // ud key ... fifos fifo key | 270 | lua_pushvalue( L, 2); // ud key ... fifos fifo key |
271 | lua_pushvalue( L, -2); // ud key ... fifos fifo key fifo | 271 | lua_pushvalue( L, -2); // ud key ... fifos fifo key fifo |
272 | lua_rawset( L, -4); // ud key ... fifos fifo | 272 | lua_rawset( L, -4); // ud key ... fifos fifo |
273 | } | 273 | } |
274 | lua_remove( L, -2); // ud key ... fifo | 274 | lua_remove( L, -2); // ud key ... fifo |
275 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 275 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
276 | if( fifo->limit >= 0 && fifo->count + n > fifo->limit) | 276 | if( fifo->limit >= 0 && fifo->count + n > fifo->limit) |
277 | { | 277 | { |
278 | lua_settop( L, 0); // | 278 | lua_settop( L, 0); // |
279 | lua_pushboolean( L, 0); // false | 279 | lua_pushboolean( L, 0); // false |
280 | } | 280 | } |
281 | else | 281 | else |
282 | { | 282 | { |
283 | fifo = prepare_fifo_access( L, -1); | 283 | fifo = prepare_fifo_access( L, -1); |
284 | lua_replace( L, 2); // ud fifo ... | 284 | lua_replace( L, 2); // ud fifo ... |
285 | fifo_push( L, fifo, n); // ud fifo | 285 | fifo_push( L, fifo, n); // ud fifo |
286 | lua_settop( L, 0); // | 286 | lua_settop( L, 0); // |
287 | lua_pushboolean( L, 1); // true | 287 | lua_pushboolean( L, 1); // true |
288 | } | 288 | } |
289 | return 1; | 289 | return 1; |
290 | } | 290 | } |
291 | 291 | ||
292 | // in: linda_ud, key [, key]? | 292 | // in: linda_ud, key [, key]? |
293 | // out: (key, val) or nothing | 293 | // out: (key, val) or nothing |
294 | int keepercall_receive( lua_State* L) | 294 | int keepercall_receive( lua_State* L) |
295 | { | 295 | { |
296 | int top = lua_gettop( L); | 296 | int top = lua_gettop( L); |
297 | int i; | 297 | int i; |
298 | push_table( L, 1); // ud keys fifos | 298 | push_table( L, 1); // ud keys fifos |
299 | lua_replace( L, 1); // fifos keys | 299 | lua_replace( L, 1); // fifos keys |
300 | for( i = 2; i <= top; ++ i) | 300 | for( i = 2; i <= top; ++ i) |
301 | { | 301 | { |
302 | keeper_fifo* fifo; | 302 | keeper_fifo* fifo; |
303 | lua_pushvalue( L, i); // fifos keys key[i] | 303 | lua_pushvalue( L, i); // fifos keys key[i] |
304 | lua_rawget( L, 1); // fifos keys fifo | 304 | lua_rawget( L, 1); // fifos keys fifo |
305 | fifo = prepare_fifo_access( L, -1); // fifos keys fifo | 305 | fifo = prepare_fifo_access( L, -1); // fifos keys fifo |
306 | if( fifo != NULL && fifo->count > 0) | 306 | if( fifo != NULL && fifo->count > 0) |
307 | { | 307 | { |
308 | fifo_pop( L, fifo, 1); // fifos keys val | 308 | fifo_pop( L, fifo, 1); // fifos keys val |
309 | if( !lua_isnil( L, -1)) | 309 | if( !lua_isnil( L, -1)) |
310 | { | 310 | { |
311 | lua_replace( L, 1); // val keys | 311 | lua_replace( L, 1); // val keys |
312 | lua_settop( L, i); // val keys key[i] | 312 | lua_settop( L, i); // val keys key[i] |
313 | if( i != 2) | 313 | if( i != 2) |
314 | { | 314 | { |
315 | lua_replace( L, 2); // val key keys | 315 | lua_replace( L, 2); // val key keys |
316 | lua_settop( L, 2); // val key | 316 | lua_settop( L, 2); // val key |
317 | } | 317 | } |
318 | lua_insert( L, 1); // key, val | 318 | lua_insert( L, 1); // key, val |
319 | return 2; | 319 | return 2; |
320 | } | 320 | } |
321 | } | 321 | } |
322 | lua_settop( L, top); // data keys | 322 | lua_settop( L, top); // data keys |
323 | } | 323 | } |
324 | // nothing to receive | 324 | // nothing to receive |
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | //in: linda_ud key mincount [maxcount] | 328 | //in: linda_ud key mincount [maxcount] |
329 | int keepercall_receive_batched( lua_State* L) | 329 | int keepercall_receive_batched( lua_State* L) |
330 | { | 330 | { |
331 | lua_Integer const min_count = lua_tointeger( L, 3); | 331 | lua_Integer const min_count = lua_tointeger( L, 3); |
332 | if( min_count > 0) | 332 | if( min_count > 0) |
333 | { | 333 | { |
334 | keeper_fifo* fifo; | 334 | keeper_fifo* fifo; |
335 | lua_Integer const max_count = luaL_optinteger( L, 4, min_count); | 335 | lua_Integer const max_count = luaL_optinteger( L, 4, min_count); |
336 | lua_settop( L, 2); // ud key | 336 | lua_settop( L, 2); // ud key |
337 | lua_insert( L, 1); // key ud | 337 | lua_insert( L, 1); // key ud |
338 | push_table( L, 2); // key ud fifos | 338 | push_table( L, 2); // key ud fifos |
339 | lua_remove( L, 2); // key fifos | 339 | lua_remove( L, 2); // key fifos |
340 | lua_pushvalue( L, 1); // key fifos key | 340 | lua_pushvalue( L, 1); // key fifos key |
341 | lua_rawget( L, 2); // key fifos fifo | 341 | lua_rawget( L, 2); // key fifos fifo |
342 | lua_remove( L, 2); // key fifo | 342 | lua_remove( L, 2); // key fifo |
343 | fifo = prepare_fifo_access( L, 2); // key fifo | 343 | fifo = prepare_fifo_access( L, 2); // key fifo |
344 | if( fifo != NULL && fifo->count >= min_count) | 344 | if( fifo != NULL && fifo->count >= min_count) |
345 | { | 345 | { |
346 | fifo_pop( L, fifo, __min( max_count, fifo->count)); // key ... | 346 | fifo_pop( L, fifo, __min( max_count, fifo->count)); // key ... |
347 | } | 347 | } |
348 | else | 348 | else |
349 | { | 349 | { |
350 | lua_settop( L, 0); | 350 | lua_settop( L, 0); |
351 | } | 351 | } |
352 | return lua_gettop( L); | 352 | return lua_gettop( L); |
353 | } | 353 | } |
354 | else | 354 | else |
355 | { | 355 | { |
356 | return 0; | 356 | return 0; |
357 | } | 357 | } |
358 | } | 358 | } |
359 | 359 | ||
360 | // in: linda_ud key n | 360 | // in: linda_ud key n |
361 | // out: true or nil | 361 | // out: true or nil |
362 | int keepercall_limit( lua_State* L) | 362 | int keepercall_limit( lua_State* L) |
363 | { | 363 | { |
364 | keeper_fifo* fifo; | 364 | keeper_fifo* fifo; |
365 | lua_Integer limit = lua_tointeger( L, 3); | 365 | lua_Integer limit = lua_tointeger( L, 3); |
366 | push_table( L, 1); // ud key n fifos | 366 | push_table( L, 1); // ud key n fifos |
367 | lua_replace( L, 1); // fifos key n | 367 | lua_replace( L, 1); // fifos key n |
368 | lua_pop( L, 1); // fifos key | 368 | lua_pop( L, 1); // fifos key |
369 | lua_pushvalue( L, -1); // fifos key key | 369 | lua_pushvalue( L, -1); // fifos key key |
370 | lua_rawget( L, -3); // fifos key fifo|nil | 370 | lua_rawget( L, -3); // fifos key fifo|nil |
371 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 371 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
372 | if( fifo == NULL) | 372 | if( fifo == NULL) |
373 | { // fifos key nil | 373 | { // fifos key nil |
374 | lua_pop( L, 1); // fifos key | 374 | lua_pop( L, 1); // fifos key |
375 | fifo_new( L); // fifos key fifo | 375 | fifo_new( L); // fifos key fifo |
376 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 376 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
377 | lua_rawset( L, -3); // fifos | 377 | lua_rawset( L, -3); // fifos |
378 | } | 378 | } |
379 | // remove any clutter on the stack | 379 | // remove any clutter on the stack |
380 | lua_settop( L, 0); | 380 | lua_settop( L, 0); |
381 | // return true if we decide that blocked threads waiting to write on that key should be awakened | 381 | // 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 | 382 | // this is the case if we detect the key was full but it is no longer the case |
383 | if( | 383 | if( |
384 | ((fifo->limit >= 0) && (fifo->count >= fifo->limit)) // the key was full if limited and count exceeded the previous limit | 384 | ((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 | 385 | && ((limit < 0) || (fifo->count < limit)) // the key is not full if unlimited or count is lower than the new limit |
386 | ) | 386 | ) |
387 | { | 387 | { |
388 | lua_pushboolean( L, 1); | 388 | lua_pushboolean( L, 1); |
389 | } | 389 | } |
390 | // set the new limit | 390 | // set the new limit |
391 | fifo->limit = limit; | 391 | fifo->limit = limit; |
392 | // return 0 or 1 value | 392 | // return 0 or 1 value |
393 | return lua_gettop( L); | 393 | return lua_gettop( L); |
394 | } | 394 | } |
395 | 395 | ||
396 | //in: linda_ud key [[val] ...] | 396 | //in: linda_ud key [[val] ...] |
397 | //out: true or nil | 397 | //out: true or nil |
398 | int keepercall_set( lua_State* L) | 398 | int keepercall_set( lua_State* L) |
399 | { | 399 | { |
400 | bool_t should_wake_writers = FALSE; | 400 | bool_t should_wake_writers = FALSE; |
401 | STACK_GROW( L, 6); | 401 | STACK_GROW( L, 6); |
402 | 402 | ||
403 | // retrieve fifos associated with the linda | 403 | // retrieve fifos associated with the linda |
404 | push_table( L, 1); // ud key [val [, ...]] fifos | 404 | push_table( L, 1); // ud key [val [, ...]] fifos |
405 | lua_replace( L, 1); // fifos key [val [, ...]] | 405 | lua_replace( L, 1); // fifos key [val [, ...]] |
406 | 406 | ||
407 | // make sure we have a value on the stack | 407 | // make sure we have a value on the stack |
408 | if( lua_gettop( L) == 2) // fifos key | 408 | if( lua_gettop( L) == 2) // fifos key |
409 | { | 409 | { |
410 | keeper_fifo* fifo; | 410 | keeper_fifo* fifo; |
411 | lua_pushvalue( L, -1); // fifos key key | 411 | lua_pushvalue( L, -1); // fifos key key |
412 | 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! | 413 | // 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); | 414 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
415 | if( fifo != NULL) // might be NULL if we set a nonexistent key to nil | 415 | if( fifo != NULL) // might be NULL if we set a nonexistent key to nil |
416 | { // fifos key fifo | 416 | { // fifos key fifo |
417 | if( fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it | 417 | if( fifo->limit < 0) // fifo limit value is the default (unlimited): we can totally remove it |
418 | { | 418 | { |
419 | lua_pop( L, 1); // fifos key | 419 | lua_pop( L, 1); // fifos key |
420 | lua_pushnil( L); // fifos key nil | 420 | lua_pushnil( L); // fifos key nil |
421 | lua_rawset( L, -3); // fifos | 421 | lua_rawset( L, -3); // fifos |
422 | } | 422 | } |
423 | else | 423 | else |
424 | { | 424 | { |
425 | // we create room if the fifo was full but it is no longer the case | 425 | // 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); | 426 | should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); |
427 | lua_remove( L, -2); // fifos fifo | 427 | lua_remove( L, -2); // fifos fifo |
428 | lua_newtable( L); // fifos fifo {} | 428 | lua_newtable( L); // fifos fifo {} |
429 | lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos fifo | 429 | lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos fifo |
430 | fifo->first = 1; | 430 | fifo->first = 1; |
431 | fifo->count = 0; | 431 | fifo->count = 0; |
432 | } | 432 | } |
433 | } | 433 | } |
434 | } | 434 | } |
435 | else // set/replace contents stored at the specified key? | 435 | else // set/replace contents stored at the specified key? |
436 | { | 436 | { |
437 | lua_Integer count = lua_gettop( L) - 2; // number of items we want to store | 437 | lua_Integer count = lua_gettop( L) - 2; // number of items we want to store |
438 | keeper_fifo* fifo; // fifos key [val [, ...]] | 438 | keeper_fifo* fifo; // fifos key [val [, ...]] |
439 | lua_pushvalue( L, 2); // fifos key [val [, ...]] key | 439 | lua_pushvalue( L, 2); // fifos key [val [, ...]] key |
440 | lua_rawget( L, 1); // fifos key [val [, ...]] fifo|nil | 440 | lua_rawget( L, 1); // fifos key [val [, ...]] fifo|nil |
441 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | 441 | fifo = (keeper_fifo*) lua_touserdata( L, -1); |
442 | if( fifo == NULL) // can be NULL if we store a value at a new key | 442 | if( fifo == NULL) // can be NULL if we store a value at a new key |
443 | { // fifos key [val [, ...]] nil | 443 | { // fifos key [val [, ...]] nil |
444 | // no need to wake writers in that case, because a writer can't wait on an inexistent key | 444 | // 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 [, ...]] | 445 | lua_pop( L, 1); // fifos key [val [, ...]] |
446 | fifo_new( L); // fifos key [val [, ...]] fifo | 446 | fifo_new( L); // fifos key [val [, ...]] fifo |
447 | lua_pushvalue( L, 2); // fifos key [val [, ...]] fifo key | 447 | lua_pushvalue( L, 2); // fifos key [val [, ...]] fifo key |
448 | lua_pushvalue( L, -2); // fifos key [val [, ...]] fifo key fifo | 448 | lua_pushvalue( L, -2); // fifos key [val [, ...]] fifo key fifo |
449 | lua_rawset( L, 1); // fifos key [val [, ...]] fifo | 449 | lua_rawset( L, 1); // fifos key [val [, ...]] fifo |
450 | } | 450 | } |
451 | else // the fifo exists, we just want to update its contents | 451 | else // the fifo exists, we just want to update its contents |
452 | { // fifos key [val [, ...]] fifo | 452 | { // fifos key [val [, ...]] fifo |
453 | // we create room if the fifo was full but it is no longer the case | 453 | // 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); | 454 | 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! | 455 | // 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 {} | 456 | lua_newtable( L); // fifos key [val [, ...]] fifo {} |
457 | lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos key [val [, ...]] fifo | 457 | lua_setiuservalue( L, -2, CONTENTS_TABLE); // fifos key [val [, ...]] fifo |
458 | fifo->first = 1; | 458 | fifo->first = 1; |
459 | fifo->count = 0; | 459 | fifo->count = 0; |
460 | } | 460 | } |
461 | fifo = prepare_fifo_access( L, -1); | 461 | fifo = prepare_fifo_access( L, -1); |
462 | // move the fifo below the values we want to store | 462 | // move the fifo below the values we want to store |
463 | lua_insert( L, 3); // fifos key fifo [val [, ...]] | 463 | lua_insert( L, 3); // fifos key fifo [val [, ...]] |
464 | fifo_push( L, fifo, count); // fifos key fifo | 464 | fifo_push( L, fifo, count); // fifos key fifo |
465 | } | 465 | } |
466 | return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; | 466 | return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; |
467 | } | 467 | } |
468 | 468 | ||
469 | // in: linda_ud key [count] | 469 | // in: linda_ud key [count] |
470 | // out: at most <count> values | 470 | // out: at most <count> values |
471 | int keepercall_get( lua_State* L) | 471 | int keepercall_get( lua_State* L) |
472 | { | 472 | { |
473 | keeper_fifo* fifo; | 473 | keeper_fifo* fifo; |
474 | lua_Integer count = 1; | 474 | lua_Integer count = 1; |
475 | if( lua_gettop( L) == 3) // ud key count | 475 | if( lua_gettop( L) == 3) // ud key count |
476 | { | 476 | { |
477 | count = lua_tointeger( L, 3); | 477 | count = lua_tointeger( L, 3); |
478 | lua_pop( L, 1); // ud key | 478 | lua_pop( L, 1); // ud key |
479 | } | 479 | } |
480 | push_table( L, 1); // ud key fifos | 480 | push_table( L, 1); // ud key fifos |
481 | lua_replace( L, 1); // fifos key | 481 | lua_replace( L, 1); // fifos key |
482 | lua_rawget( L, 1); // fifos fifo | 482 | lua_rawget( L, 1); // fifos fifo |
483 | fifo = prepare_fifo_access( L, -1); // fifos fifo | 483 | fifo = prepare_fifo_access( L, -1); // fifos fifo |
484 | if( fifo != NULL && fifo->count > 0) | 484 | if( fifo != NULL && fifo->count > 0) |
485 | { | 485 | { |
486 | lua_remove( L, 1); // fifo | 486 | lua_remove( L, 1); // fifo |
487 | count = __min( count, fifo->count); | 487 | count = __min( count, fifo->count); |
488 | // read <count> value off the fifo | 488 | // read <count> value off the fifo |
489 | fifo_peek( L, fifo, count); // fifo ... | 489 | fifo_peek( L, fifo, count); // fifo ... |
490 | return (int) count; | 490 | return (int) count; |
491 | } | 491 | } |
492 | // no fifo was ever registered for this key, or it is empty | 492 | // no fifo was ever registered for this key, or it is empty |
493 | return 0; | 493 | return 0; |
494 | } | 494 | } |
495 | 495 | ||
496 | // in: linda_ud [, key [, ...]] | 496 | // in: linda_ud [, key [, ...]] |
497 | int keepercall_count( lua_State* L) | 497 | int keepercall_count( lua_State* L) |
498 | { | 498 | { |
499 | push_table( L, 1); // ud keys fifos | 499 | push_table( L, 1); // ud keys fifos |
500 | switch( lua_gettop( L)) | 500 | switch( lua_gettop( L)) |
501 | { | 501 | { |
502 | // no key is specified: return a table giving the count of all known keys | 502 | // no key is specified: return a table giving the count of all known keys |
503 | case 2: // ud fifos | 503 | case 2: // ud fifos |
504 | lua_newtable( L); // ud fifos out | 504 | lua_newtable( L); // ud fifos out |
505 | lua_replace( L, 1); // out fifos | 505 | lua_replace( L, 1); // out fifos |
506 | lua_pushnil( L); // out fifos nil | 506 | lua_pushnil( L); // out fifos nil |
507 | while( lua_next( L, 2)) // out fifos key fifo | 507 | while( lua_next( L, 2)) // out fifos key fifo |
508 | { | 508 | { |
509 | keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo | 509 | keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo |
510 | lua_pop( L, 1); // out fifos key | 510 | lua_pop( L, 1); // out fifos key |
511 | lua_pushvalue( L, -1); // out fifos key key | 511 | lua_pushvalue( L, -1); // out fifos key key |
512 | lua_pushinteger( L, fifo->count); // out fifos key key count | 512 | lua_pushinteger( L, fifo->count); // out fifos key key count |
513 | lua_rawset( L, -5); // out fifos key | 513 | lua_rawset( L, -5); // out fifos key |
514 | } | 514 | } |
515 | lua_pop( L, 1); // out | 515 | lua_pop( L, 1); // out |
516 | break; | 516 | break; |
517 | 517 | ||
518 | // 1 key is specified: return its count | 518 | // 1 key is specified: return its count |
519 | case 3: // ud key fifos | 519 | case 3: // ud key fifos |
520 | { | 520 | { |
521 | keeper_fifo* fifo; | 521 | keeper_fifo* fifo; |
522 | lua_replace( L, 1); // fifos key | 522 | lua_replace( L, 1); // fifos key |
523 | lua_rawget( L, -2); // fifos fifo|nil | 523 | lua_rawget( L, -2); // fifos fifo|nil |
524 | if( lua_isnil( L, -1)) // the key is unknown | 524 | if( lua_isnil( L, -1)) // the key is unknown |
525 | { // fifos nil | 525 | { // fifos nil |
526 | lua_remove( L, -2); // nil | 526 | lua_remove( L, -2); // nil |
527 | } | 527 | } |
528 | else // the key is known | 528 | else // the key is known |
529 | { // fifos fifo | 529 | { // fifos fifo |
530 | fifo = prepare_fifo_access( L, -1); // fifos fifo | 530 | fifo = prepare_fifo_access( L, -1); // fifos fifo |
531 | lua_pushinteger( L, fifo->count); // fifos fifo count | 531 | lua_pushinteger( L, fifo->count); // fifos fifo count |
532 | lua_replace( L, -3); // count fifo | 532 | lua_replace( L, -3); // count fifo |
533 | lua_pop( L, 1); // count | 533 | lua_pop( L, 1); // count |
534 | } | 534 | } |
535 | } | 535 | } |
536 | break; | 536 | break; |
537 | 537 | ||
538 | // a variable number of keys is specified: return a table of their counts | 538 | // a variable number of keys is specified: return a table of their counts |
539 | default: // ud keys fifos | 539 | default: // ud keys fifos |
540 | lua_newtable( L); // ud keys fifos out | 540 | lua_newtable( L); // ud keys fifos out |
541 | lua_replace( L, 1); // out keys fifos | 541 | 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 | 542 | // 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 | 543 | lua_insert( L, 2); // out fifos keys |
544 | while( lua_gettop( L) > 2) | 544 | while( lua_gettop( L) > 2) |
545 | { | 545 | { |
546 | keeper_fifo* fifo; | 546 | keeper_fifo* fifo; |
547 | lua_pushvalue( L, -1); // out fifos keys key | 547 | lua_pushvalue( L, -1); // out fifos keys key |
548 | lua_rawget( L, 2); // out fifos keys fifo|nil | 548 | lua_rawget( L, 2); // out fifos keys fifo|nil |
549 | fifo = prepare_fifo_access( L, -1); // out fifos keys fifo|nil | 549 | fifo = prepare_fifo_access( L, -1); // out fifos keys fifo|nil |
550 | lua_pop( L, 1); // out fifos keys | 550 | lua_pop( L, 1); // out fifos keys |
551 | if( fifo != NULL) // the key is known | 551 | if( fifo != NULL) // the key is known |
552 | { | 552 | { |
553 | lua_pushinteger( L, fifo->count); // out fifos keys count | 553 | lua_pushinteger( L, fifo->count); // out fifos keys count |
554 | lua_rawset( L, 1); // out fifos keys | 554 | lua_rawset( L, 1); // out fifos keys |
555 | } | 555 | } |
556 | else // the key is unknown | 556 | else // the key is unknown |
557 | { | 557 | { |
558 | lua_pop( L, 1); // out fifos keys | 558 | lua_pop( L, 1); // out fifos keys |
559 | } | 559 | } |
560 | } | 560 | } |
561 | lua_pop( L, 1); // out | 561 | lua_pop( L, 1); // out |
562 | } | 562 | } |
563 | ASSERT_L( lua_gettop( L) == 1); | 563 | ASSERT_L( lua_gettop( L) == 1); |
564 | return 1; | 564 | return 1; |
565 | } | 565 | } |
566 | 566 | ||
567 | //################################################################################### | 567 | //################################################################################### |
@@ -582,41 +582,41 @@ int keepercall_count( lua_State* L) | |||
582 | // called as __gc for the keepers array userdata | 582 | // called as __gc for the keepers array userdata |
583 | void close_keepers( Universe* U, lua_State* L) | 583 | void close_keepers( Universe* U, lua_State* L) |
584 | { | 584 | { |
585 | if( U->keepers != NULL) | 585 | if( U->keepers != NULL) |
586 | { | 586 | { |
587 | int i; | 587 | int i; |
588 | int nbKeepers = U->keepers->nb_keepers; | 588 | 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 | 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 |
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 | 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 |
591 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success | 591 | // 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 | 592 | // which is early-outed with a U->keepers->nbKeepers null-check |
593 | U->keepers->nb_keepers = 0; | 593 | U->keepers->nb_keepers = 0; |
594 | for( i = 0; i < nbKeepers; ++ i) | 594 | for( i = 0; i < nbKeepers; ++ i) |
595 | { | 595 | { |
596 | lua_State* K = U->keepers->keeper_array[i].L; | 596 | lua_State* K = U->keepers->keeper_array[i].L; |
597 | U->keepers->keeper_array[i].L = NULL; | 597 | U->keepers->keeper_array[i].L = NULL; |
598 | if( K != NULL) | 598 | if( K != NULL) |
599 | { | 599 | { |
600 | lua_close( K); | 600 | lua_close( K); |
601 | } | 601 | } |
602 | else | 602 | else |
603 | { | 603 | { |
604 | // detected partial init: destroy only the mutexes that got initialized properly | 604 | // detected partial init: destroy only the mutexes that got initialized properly |
605 | nbKeepers = i; | 605 | nbKeepers = i; |
606 | } | 606 | } |
607 | } | 607 | } |
608 | for( i = 0; i < nbKeepers; ++ i) | 608 | for( i = 0; i < nbKeepers; ++ i) |
609 | { | 609 | { |
610 | MUTEX_FREE( &U->keepers->keeper_array[i].keeper_cs); | 610 | MUTEX_FREE( &U->keepers->keeper_array[i].keeper_cs); |
611 | } | 611 | } |
612 | // free the keeper bookkeeping structure | 612 | // free the keeper bookkeeping structure |
613 | { | 613 | { |
614 | void* allocUD; | 614 | void* allocUD; |
615 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | 615 | lua_Alloc allocF = lua_getallocf( L, &allocUD); |
616 | allocF( allocUD, U->keepers, sizeof( Keepers) + (nbKeepers - 1) * sizeof( Keeper), 0); | 616 | allocF( allocUD, U->keepers, sizeof( Keepers) + (nbKeepers - 1) * sizeof( Keeper), 0); |
617 | U->keepers = NULL; | 617 | U->keepers = NULL; |
618 | } | 618 | } |
619 | } | 619 | } |
620 | } | 620 | } |
621 | 621 | ||
622 | /* | 622 | /* |
@@ -632,156 +632,156 @@ void close_keepers( Universe* U, lua_State* L) | |||
632 | */ | 632 | */ |
633 | void init_keepers( Universe* U, lua_State* L) | 633 | void init_keepers( Universe* U, lua_State* L) |
634 | { | 634 | { |
635 | int i; | 635 | int i; |
636 | int nb_keepers; | 636 | int nb_keepers; |
637 | void* allocUD; | 637 | void* allocUD; |
638 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | 638 | lua_Alloc allocF = lua_getallocf( L, &allocUD); |
639 | 639 | ||
640 | STACK_CHECK( L, 0); // L K | 640 | STACK_CHECK( L, 0); // L K |
641 | lua_getfield( L, 1, "nb_keepers"); // nb_keepers | 641 | lua_getfield( L, 1, "nb_keepers"); // nb_keepers |
642 | nb_keepers = (int) lua_tointeger( L, -1); | 642 | nb_keepers = (int) lua_tointeger( L, -1); |
643 | lua_pop( L, 1); // | 643 | lua_pop( L, 1); // |
644 | if( nb_keepers < 1) | 644 | if( nb_keepers < 1) |
645 | { | 645 | { |
646 | (void) luaL_error( L, "Bad number of keepers (%d)", nb_keepers); | 646 | (void) luaL_error( L, "Bad number of keepers (%d)", nb_keepers); |
647 | } | 647 | } |
648 | 648 | ||
649 | // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states | 649 | // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states |
650 | { | 650 | { |
651 | size_t const bytes = sizeof( Keepers) + (nb_keepers - 1) * sizeof( Keeper); | 651 | size_t const bytes = sizeof( Keepers) + (nb_keepers - 1) * sizeof( Keeper); |
652 | U->keepers = (Keepers*) allocF( allocUD, NULL, 0, bytes); | 652 | U->keepers = (Keepers*) allocF( allocUD, NULL, 0, bytes); |
653 | if( U->keepers == NULL) | 653 | if( U->keepers == NULL) |
654 | { | 654 | { |
655 | (void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory"); | 655 | (void) luaL_error( L, "init_keepers() failed while creating keeper array; out of memory"); |
656 | return; | 656 | return; |
657 | } | 657 | } |
658 | memset( U->keepers, 0, bytes); | 658 | memset( U->keepers, 0, bytes); |
659 | U->keepers->nb_keepers = nb_keepers; | 659 | U->keepers->nb_keepers = nb_keepers; |
660 | } | 660 | } |
661 | for( i = 0; i < nb_keepers; ++ i) // keepersUD | 661 | for( i = 0; i < nb_keepers; ++ i) // keepersUD |
662 | { | 662 | { |
663 | // note that we will leak K if we raise an error later | 663 | // note that we will leak K if we raise an error later |
664 | lua_State* K = create_state( U, L); | 664 | lua_State* K = create_state( U, L); |
665 | if( K == NULL) | 665 | if( K == NULL) |
666 | { | 666 | { |
667 | (void) luaL_error( L, "init_keepers() failed while creating keeper states; out of memory"); | 667 | (void) luaL_error( L, "init_keepers() failed while creating keeper states; out of memory"); |
668 | return; | 668 | return; |
669 | } | 669 | } |
670 | 670 | ||
671 | U->keepers->keeper_array[i].L = K; | 671 | U->keepers->keeper_array[i].L = K; |
672 | // we can trigger a GC from inside keeper_call(), where a keeper is acquired | 672 | // 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. | 673 | // from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread. |
674 | // therefore, we need a recursive mutex. | 674 | // therefore, we need a recursive mutex. |
675 | MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); | 675 | MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); |
676 | 676 | ||
677 | STACK_CHECK( K, 0); | 677 | STACK_CHECK( K, 0); |
678 | 678 | ||
679 | // copy the universe pointer in the keeper itself | 679 | // copy the universe pointer in the keeper itself |
680 | universe_store( K, U); | 680 | universe_store( K, U); |
681 | STACK_MID( K, 0); | 681 | STACK_MID( K, 0); |
682 | 682 | ||
683 | // make sure 'package' is initialized in keeper states, so that we have require() | 683 | // make sure 'package' is initialized in keeper states, so that we have require() |
684 | // this because this is needed when transferring deep userdata object | 684 | // this because this is needed when transferring deep userdata object |
685 | luaL_requiref( K, "package", luaopen_package, 1); // package | 685 | luaL_requiref( K, "package", luaopen_package, 1); // package |
686 | lua_pop( K, 1); // | 686 | lua_pop( K, 1); // |
687 | STACK_MID( K, 0); | 687 | STACK_MID( K, 0); |
688 | serialize_require( DEBUGSPEW_PARAM_COMMA( U) K); | 688 | serialize_require( DEBUGSPEW_PARAM_COMMA( U) K); |
689 | STACK_MID( K, 0); | 689 | STACK_MID( K, 0); |
690 | 690 | ||
691 | // copy package.path and package.cpath from the source state | 691 | // copy package.path and package.cpath from the source state |
692 | lua_getglobal( L, "package"); // "..." keepersUD package | 692 | lua_getglobal( L, "package"); // "..." keepersUD package |
693 | if( !lua_isnil( L, -1)) | 693 | if( !lua_isnil( L, -1)) |
694 | { | 694 | { |
695 | // when copying with mode eLM_ToKeeper, error message is pushed at the top of the stack, not raised immediately | 695 | // 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)) | 696 | if( luaG_inter_copy_package( U, L, K, -1, eLM_ToKeeper)) |
697 | { | 697 | { |
698 | // if something went wrong, the error message is at the top of the stack | 698 | // if something went wrong, the error message is at the top of the stack |
699 | lua_remove( L, -2); // error_msg | 699 | lua_remove( L, -2); // error_msg |
700 | (void) lua_error( L); | 700 | (void) lua_error( L); |
701 | return; | 701 | return; |
702 | } | 702 | } |
703 | } | 703 | } |
704 | lua_pop( L, 1); // | 704 | lua_pop( L, 1); // |
705 | STACK_MID( L, 0); | 705 | STACK_MID( L, 0); |
706 | 706 | ||
707 | // attempt to call on_state_create(), if we have one and it is a C function | 707 | // 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) | 708 | // (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 | 709 | // will raise an error in L in case of problem |
710 | call_on_state_create( U, K, L, eLM_ToKeeper); | 710 | call_on_state_create( U, K, L, eLM_ToKeeper); |
711 | 711 | ||
712 | // to see VM name in Decoda debugger | 712 | // to see VM name in Decoda debugger |
713 | lua_pushfstring( K, "Keeper #%d", i + 1); // "Keeper #n" | 713 | lua_pushfstring( K, "Keeper #%d", i + 1); // "Keeper #n" |
714 | lua_setglobal( K, "decoda_name"); // | 714 | lua_setglobal( K, "decoda_name"); // |
715 | 715 | ||
716 | // create the fifos table in the keeper state | 716 | // create the fifos table in the keeper state |
717 | REGISTRY_SET( K, FIFOS_KEY, lua_newtable( K)); | 717 | REGISTRY_SET( K, FIFOS_KEY, lua_newtable( K)); |
718 | STACK_END( K, 0); | 718 | STACK_END( K, 0); |
719 | } | 719 | } |
720 | STACK_END( L, 0); | 720 | STACK_END( L, 0); |
721 | } | 721 | } |
722 | 722 | ||
723 | // should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call) | 723 | // should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call) |
724 | Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_) | 724 | Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_) |
725 | { | 725 | { |
726 | int const nbKeepers = keepers_->nb_keepers; | 726 | int const nbKeepers = keepers_->nb_keepers; |
727 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); | 727 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); |
728 | return &keepers_->keeper_array[i]; | 728 | return &keepers_->keeper_array[i]; |
729 | } | 729 | } |
730 | 730 | ||
731 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) | 731 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) |
732 | { | 732 | { |
733 | int const nbKeepers = keepers_->nb_keepers; | 733 | int const nbKeepers = keepers_->nb_keepers; |
734 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) | 734 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) |
735 | if( nbKeepers == 0) | 735 | if( nbKeepers == 0) |
736 | { | 736 | { |
737 | return NULL; | 737 | return NULL; |
738 | } | 738 | } |
739 | else | 739 | else |
740 | { | 740 | { |
741 | /* | 741 | /* |
742 | * Any hashing will do that maps pointers to 0..GNbKeepers-1 | 742 | * Any hashing will do that maps pointers to 0..GNbKeepers-1 |
743 | * consistently. | 743 | * consistently. |
744 | * | 744 | * |
745 | * Pointers are often aligned by 8 or so - ignore the low order bits | 745 | * Pointers are often aligned by 8 or so - ignore the low order bits |
746 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer | 746 | * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer |
747 | */ | 747 | */ |
748 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); | 748 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); |
749 | Keeper* K = &keepers_->keeper_array[i]; | 749 | Keeper* K = &keepers_->keeper_array[i]; |
750 | 750 | ||
751 | MUTEX_LOCK( &K->keeper_cs); | 751 | MUTEX_LOCK( &K->keeper_cs); |
752 | //++ K->count; | 752 | //++ K->count; |
753 | return K; | 753 | return K; |
754 | } | 754 | } |
755 | } | 755 | } |
756 | 756 | ||
757 | void keeper_release( Keeper* K) | 757 | void keeper_release( Keeper* K) |
758 | { | 758 | { |
759 | //-- K->count; | 759 | //-- K->count; |
760 | if( K) MUTEX_UNLOCK( &K->keeper_cs); | 760 | if( K) MUTEX_UNLOCK( &K->keeper_cs); |
761 | } | 761 | } |
762 | 762 | ||
763 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) | 763 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) |
764 | { | 764 | { |
765 | int i, n = lua_gettop( L); | 765 | int i, n = lua_gettop( L); |
766 | for( i = val_i_; i <= n; ++ i) | 766 | for( i = val_i_; i <= n; ++ i) |
767 | { | 767 | { |
768 | if( mode_ == eLM_ToKeeper) | 768 | if( mode_ == eLM_ToKeeper) |
769 | { | 769 | { |
770 | if( lua_isnil( L, i)) | 770 | if( lua_isnil( L, i)) |
771 | { | 771 | { |
772 | push_unique_key( L, NIL_SENTINEL); | 772 | push_unique_key( L, NIL_SENTINEL); |
773 | lua_replace( L, i); | 773 | lua_replace( L, i); |
774 | } | 774 | } |
775 | } | 775 | } |
776 | else | 776 | else |
777 | { | 777 | { |
778 | if( equal_unique_key( L, i, NIL_SENTINEL)) | 778 | if( equal_unique_key( L, i, NIL_SENTINEL)) |
779 | { | 779 | { |
780 | lua_pushnil( L); | 780 | lua_pushnil( L); |
781 | lua_replace( L, i); | 781 | lua_replace( L, i); |
782 | } | 782 | } |
783 | } | 783 | } |
784 | } | 784 | } |
785 | } | 785 | } |
786 | 786 | ||
787 | /* | 787 | /* |
@@ -795,31 +795,31 @@ void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mod | |||
795 | */ | 795 | */ |
796 | int keeper_call( Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, uint_t starting_index) | 796 | int keeper_call( Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, void* linda, uint_t starting_index) |
797 | { | 797 | { |
798 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; | 798 | int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0; |
799 | int const Ktos = lua_gettop( K); | 799 | int const Ktos = lua_gettop( K); |
800 | int retvals = -1; | 800 | int retvals = -1; |
801 | 801 | ||
802 | STACK_GROW( K, 2); | 802 | STACK_GROW( K, 2); |
803 | 803 | ||
804 | PUSH_KEEPER_FUNC( K, func_); | 804 | PUSH_KEEPER_FUNC( K, func_); |
805 | 805 | ||
806 | lua_pushlightuserdata( K, linda); | 806 | lua_pushlightuserdata( K, linda); |
807 | 807 | ||
808 | if( (args == 0) || luaG_inter_copy( U, L, K, args, eLM_ToKeeper) == 0) // L->K | 808 | if( (args == 0) || luaG_inter_copy( U, L, K, args, eLM_ToKeeper) == 0) // L->K |
809 | { | 809 | { |
810 | lua_call( K, 1 + args, LUA_MULTRET); | 810 | lua_call( K, 1 + args, LUA_MULTRET); |
811 | 811 | ||
812 | retvals = lua_gettop( K) - Ktos; | 812 | retvals = lua_gettop( K) - Ktos; |
813 | // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired | 813 | // note that this can raise a luaL_error while the keeper state (and its mutex) is acquired |
814 | // this may interrupt a lane, causing the destruction of the underlying OS thread | 814 | // this may interrupt a lane, causing the destruction of the underlying OS thread |
815 | // after this, another lane making use of this keeper can get an error code from the mutex-locking function | 815 | // after this, another lane making use of this keeper can get an error code from the mutex-locking function |
816 | // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) | 816 | // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) |
817 | if( (retvals > 0) && luaG_inter_move( U, K, L, retvals, eLM_FromKeeper) != 0) // K->L | 817 | if( (retvals > 0) && luaG_inter_move( U, K, L, retvals, eLM_FromKeeper) != 0) // K->L |
818 | { | 818 | { |
819 | retvals = -1; | 819 | retvals = -1; |
820 | } | 820 | } |
821 | } | 821 | } |
822 | // whatever happens, restore the stack to where it was at the origin | 822 | // whatever happens, restore the stack to where it was at the origin |
823 | lua_settop( K, Ktos); | 823 | lua_settop( K, Ktos); |
824 | return retvals; | 824 | return retvals; |
825 | } | 825 | } |