summaryrefslogtreecommitdiff
path: root/src/keeper.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2012-08-22 21:36:37 +0200
committerBenoit Germain <bnt.germain@gmail.com>2012-08-22 21:36:37 +0200
commitf0b1c6d629464c0a59ac78382d86f434e74c2162 (patch)
treee6788f8e7c0e859cd5f8d9254a922e187d9e7938 /src/keeper.c
parenta9075ff6cf43e99cee994f5e77d0e1e54cb8dbac (diff)
downloadlanes-3.2.0.tar.gz
lanes-3.2.0.tar.bz2
lanes-3.2.0.zip
lanes version 3.2.0v3.2.0
* keeper internals implemented in C instead of Lua for better performances * fixed arguments checks in linda:limit() and linda:set()
Diffstat (limited to 'src/keeper.c')
-rw-r--r--src/keeper.c390
1 files changed, 383 insertions, 7 deletions
diff --git a/src/keeper.c b/src/keeper.c
index 444a98e..86c69e2 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -14,7 +14,7 @@
14 --[[ 14 --[[
15 =============================================================================== 15 ===============================================================================
16 16
17 Copyright (C) 2011 Benoit Germain <bnt.germain@gmail.com> 17 Copyright (C) 2011-2012 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
@@ -50,6 +50,374 @@
50#include "tools.h" 50#include "tools.h"
51#include "keeper.h" 51#include "keeper.h"
52 52
53#if KEEPER_MODEL == KEEPER_MODEL_C
54//###################################################################################
55// Keeper implementation
56//###################################################################################
57
58typedef struct
59{
60 int first;
61 int count;
62 int limit;
63} keeper_fifo;
64
65// replaces the fifo ud by its uservalue on the stack
66static keeper_fifo* prepare_fifo_access( lua_State* L, int idx)
67{
68 keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx);
69 if( fifo)
70 {
71 idx = lua_absindex( L, idx);
72 STACK_GROW( L, 1);
73 // we can replace the fifo userdata in the stack without fear of it being GCed, there are other references around
74 lua_getuservalue( L, idx);
75 lua_replace( L, idx);
76 }
77 return fifo;
78}
79
80// in: nothing
81// out: { first = 1, count = 0, limit = -1}
82static void fifo_new( lua_State* L)
83{
84 keeper_fifo* fifo;
85 STACK_GROW( L, 2);
86 fifo = (keeper_fifo*) lua_newuserdata( L, sizeof( keeper_fifo));
87 fifo->first = 1;
88 fifo->count = 0;
89 fifo->limit = -1;
90 lua_newtable( L);
91 lua_setuservalue( L, -2);
92}
93
94// in: expect fifo ... on top of the stack
95// out: nothing, removes all pushed values on the stack
96static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count)
97{
98 int idx = lua_gettop( L) - _count;
99 int start = fifo->first + fifo->count - 1;
100 int i;
101 // pop all additional arguments, storing them in the fifo
102 for( i = _count; i >= 1; -- i)
103 {
104 // store in the fifo the value at the top of the stack at the specified index, popping it from the stack
105 lua_rawseti( L, idx, start + i);
106 }
107 fifo->count += _count;
108}
109
110// in: fifo
111// out: ...|nothing
112// expects exactly 1 value on the stack!
113// currently only called with a count of 1, but this may change in the future
114// function assumes that there is enough data in the fifo to satisfy the request
115static void fifo_peek( lua_State* L, keeper_fifo* fifo, int _count)
116{
117 int i;
118 STACK_GROW( L, _count);
119 for( i = 0; i < _count; ++ i)
120 {
121 lua_rawgeti( L, 1, fifo->first + i);
122 }
123}
124
125// in: fifo
126// out: pushes as many items as required on the stack (function assumes they exist in sufficient number)
127static void fifo_pop( lua_State* L, keeper_fifo* fifo, int _count)
128{
129 int fifo_idx = lua_gettop( L); // ... fifo
130 int i;
131 // each iteration pushes a value on the stack!
132 STACK_GROW( L, _count + 1);
133 for( i = 0; i < _count; ++ i)
134 {
135 int at = fifo->first + i;
136 lua_rawgeti( L, fifo_idx, at); // ... fifo val
137 lua_pushnil( L); // ... fifo val nil
138 lua_rawseti( L, fifo_idx, at); // ... fifo val
139 }
140 fifo->first += _count;
141 fifo->count -= _count;
142}
143
144// in: linda_ud expected at *absolute* stack slot idx
145// out: fifos[ud]
146static void* const fifos_key = (void*) prepare_fifo_access;
147static void push_table( lua_State* L, int idx)
148{
149 STACK_GROW( L, 4);
150 STACK_CHECK( L)
151 idx = lua_absindex( L, idx);
152 lua_pushlightuserdata( L, fifos_key); // ud fifos_key
153 lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos
154 lua_pushvalue( L, idx); // ud fifos ud
155 lua_rawget( L, -2); // ud fifos fifos[ud]
156 STACK_MID( L, 2);
157 if( lua_isnil( L, -1))
158 {
159 lua_pop( L, 1); // ud fifos
160 // add a new fifos table for this linda
161 lua_newtable( L); // ud fifos fifos[ud]
162 lua_pushvalue( L, idx); // ud fifos fifos[ud] ud
163 lua_pushvalue( L, -2); // ud fifos fifos[ud] ud fifos[ud]
164 lua_rawset( L, -4); // ud fifos fifos[ud]
165 }
166 lua_remove( L, -2); // ud fifos[ud]
167 STACK_END( L, 1);
168}
169
170// in: linda_ud
171int keepercall_clear( lua_State* L)
172{
173 STACK_GROW( L, 3);
174 lua_pushlightuserdata( L, fifos_key); // ud fifos_key
175 lua_rawget( L, LUA_REGISTRYINDEX); // ud fifos
176 lua_pushvalue( L, 1); // ud fifos ud
177 lua_pushnil( L); // ud fifos ud nil
178 lua_rawset( L, -3); // ud fifos
179 lua_pop( L, 1); // ud
180 return 0;
181}
182
183
184// in: linda_ud, key, ...
185// out: true|false
186int keepercall_send( lua_State* L)
187{
188 keeper_fifo* fifo;
189 int n = lua_gettop( L) - 2;
190 push_table( L, 1); // ud key ... fifos
191 // get the fifo associated to this key in this linda, create it if it doesn't exist
192 lua_pushvalue( L, 2); // ud key ... fifos key
193 lua_rawget( L, -2); // ud key ... fifos fifo
194 if( lua_isnil( L, -1))
195 {
196 lua_pop( L, 1); // ud key ... fifos
197 fifo_new( L); // ud key ... fifos fifo
198 lua_pushvalue( L, 2); // ud key ... fifos fifo key
199 lua_pushvalue( L, -2); // ud key ... fifos fifo key fifo
200 lua_rawset( L, -4); // ud key ... fifos fifo
201 }
202 lua_remove( L, -2); // ud key ... fifo
203 fifo = (keeper_fifo*) lua_touserdata( L, -1);
204 if( fifo->limit >= 0 && fifo->count + n > fifo->limit)
205 {
206 lua_settop( L, 0); //
207 lua_pushboolean( L, 0); // false
208 }
209 else
210 {
211 fifo = prepare_fifo_access( L, -1);
212 lua_replace( L, 2); // ud fifo ...
213 fifo_push( L, fifo, n); // ud fifo
214 lua_settop( L, 0); //
215 lua_pushboolean( L, 1); // true
216 }
217 return 1;
218}
219
220// in: linda_ud, key [, key]?
221// out: (val, key) or nothing
222int keepercall_receive( lua_State* L)
223{
224 int top = lua_gettop( L);
225 int i;
226 keeper_fifo* fifo;
227 push_table( L, 1); // ud keys fifos
228 lua_replace( L, 1); // fifos keys
229 for( i = 2; i <= top; ++ i)
230 {
231 lua_pushvalue( L, i); // fifos keys key[i]
232 lua_rawget( L, 1); // fifos keys fifo
233 fifo = prepare_fifo_access( L, -1); // fifos keys fifo
234 if( fifo && fifo->count > 0)
235 {
236 fifo_pop( L, fifo, 1); // fifos keys fifo val
237 if( !lua_isnil( L, -1))
238 {
239 lua_replace( L, 1); // val keys fifo
240 if( i != 2)
241 {
242 lua_pushvalue( L, i); // val keys fifo key[i]
243 lua_replace( L, 2); // val key keys fifo
244 }
245 lua_settop( L, 2); // val key
246 return 2;
247 }
248 }
249 lua_settop( L, top); // data keys
250 }
251 // nothing to receive
252 return 0;
253}
254
255//in: linda_ud key mincount [maxcount]
256int keepercall_receive_batched( lua_State* L)
257{
258 int const min_count = (int) lua_tointeger( L, 3);
259 if( min_count > 0)
260 {
261 keeper_fifo* fifo;
262 int const max_count = (int) luaL_optinteger( L, 4, min_count);
263 lua_settop( L, 2); // ud key
264 push_table( L, 1); // ud key fifos
265 lua_replace( L, 1); // fifos key
266 lua_rawget( L, -2); // fifos fifo
267 lua_remove( L, 1); // fifo
268 fifo = prepare_fifo_access( L, 1); // fifo
269 if( fifo && fifo->count >= min_count)
270 {
271 fifo_pop( L, fifo, min( max_count, fifo->count)); // fifo ...
272 }
273 return lua_gettop( L) - 1;
274 }
275 else
276 {
277 return 0;
278 }
279}
280
281// in: linda_ud key n
282// out: nothing
283int keepercall_limit( lua_State* L)
284{
285 keeper_fifo* fifo;
286 int limit = (int) lua_tointeger( L, 3);
287 push_table( L, 1); // ud key n fifos
288 lua_replace( L, 1); // fifos key n
289 lua_pop( L, 1); // fifos key
290 lua_pushvalue( L, -1); // fifos key key
291 lua_rawget( L, -3); // fifos key fifo
292 fifo = (keeper_fifo*) lua_touserdata( L, -1);
293 if( !fifo)
294 {
295 lua_pop( L, 1); // fifos key
296 fifo_new( L); // fifos key fifo
297 fifo = (keeper_fifo*) lua_touserdata( L, -1);
298 lua_rawset( L, -3); // fifos
299 }
300 fifo->limit = limit;
301 return 0;
302}
303
304//in: linda_ud key [val]
305int keepercall_set( lua_State* L)
306{
307 // make sure we have a value on the stack
308 if( lua_gettop( L) == 2)
309 {
310 lua_pushnil( L);
311 }
312 push_table( L, 1); // ud key val fifos
313 lua_replace( L, 1); // fifos key val
314 if( !lua_isnil( L, 3)) // replace contents stored at the specified key?
315 {
316 keeper_fifo* fifo;
317 fifo_new( L); // fifos key val fifo
318 lua_pushvalue( L, 2); // fifos key val fifo key
319 lua_pushvalue( L, -2); // fifos key val fifo key fifo
320 lua_rawset( L, 1); // fifos key val fifo
321 fifo = prepare_fifo_access( L, -1);
322 lua_insert( L, -2); // fifos key fifo val
323 fifo_push( L, fifo, 1); // fifos key fifo
324 }
325 else
326 {
327 // val == nil => stack contents: fifos key nil => remove the fifo associated with the current key
328 lua_rawset( L, 1); // fifos
329 }
330 return 0;
331}
332
333// in: linda_ud key
334int keepercall_get( lua_State* L)
335{
336 keeper_fifo* fifo;
337 push_table( L, 1); // ud key fifos
338 lua_replace( L, 1); // fifos key
339 lua_rawget( L, 1); // fifos fifo
340 fifo = prepare_fifo_access( L, -1); // fifos fifo
341 if( fifo && fifo->count > 0)
342 {
343 lua_remove( L, 1); // fifo
344 // read one value off the fifo
345 fifo_peek( L, fifo, 1); // fifo ...
346 return 1;
347 }
348 // no fifo was ever registered for this key, or it is empty
349 return 0;
350}
351
352// in: linda_ud [, key [, ...]]
353int keepercall_count( lua_State* L)
354{
355 int top;
356 push_table( L, 1); // ud keys fifos
357 switch( lua_gettop( L))
358 {
359 // no key is specified: return a table giving the count of all known keys
360 case 2: // ud fifos
361 lua_newtable( L); // ud fifos out
362 lua_replace( L, 1); // out fifos
363 lua_pushnil( L); // out fifos nil
364 while( lua_next( L, 2)) // out fifos key fifo
365 {
366 keeper_fifo* fifo = prepare_fifo_access( L, -1); // out fifos key fifo
367 lua_pop( L, 1); // out fifos key
368 lua_pushvalue( L, -1); // out fifos key key
369 lua_pushinteger( L, fifo->count); // out fifos key key count
370 lua_rawset( L, -5); // out fifos key
371 }
372 lua_pop( L, 1); // out
373 break;
374
375 // 1 key is specified: return its count
376 case 3: // ud key fifos
377 {
378 keeper_fifo* fifo;
379 lua_replace( L, 1); // fifos key
380 lua_rawget( L, -2); // fifos fifo
381 fifo = prepare_fifo_access( L, -1); // fifos fifo
382 lua_pushinteger( L, fifo->count); // fifos fifo count
383 lua_replace( L, -3); // count fifo
384 lua_pop( L, 1); // count
385 }
386 break;
387
388 // a variable number of keys is specified: return a table of their counts
389 default: // ud keys fifos
390 lua_newtable( L); // ud keys fifos out
391 lua_replace( L, 1); // out keys fifos
392 // shifts all keys up in the stack. potentially slow if there are a lot of them, but then it should be bearable
393 lua_insert( L, 2); // out fifos keys
394 while( (top = lua_gettop( L)) > 2)
395 {
396 keeper_fifo* fifo;
397 lua_pushvalue( L, -1); // out fifos keys key
398 lua_rawget( L, 2); // out fifos keys fifo
399 fifo = prepare_fifo_access( L, -1); // out fifos keys fifo
400 lua_pop( L, 1); // out fifos keys
401 if( fifo)
402 {
403 lua_pushinteger( L, fifo->count); // out fifos keys count
404 lua_rawset( L, 1); // out fifos keys
405 }
406 else
407 {
408 lua_pop( L, 1); // out fifos keys
409 }
410 }
411 lua_pop( L, 1); // out
412 }
413 return 1;
414}
415#endif // KEEPER_MODEL == KEEPER_MODEL_C
416
417//###################################################################################
418// Keeper API, accessed from linda methods
419//###################################################################################
420
53/*---=== Keeper states ===--- 421/*---=== Keeper states ===---
54*/ 422*/
55 423
@@ -115,6 +483,14 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
115 lua_concat( K, 2); 483 lua_concat( K, 2);
116 lua_setglobal( K, "decoda_name"); 484 lua_setglobal( K, "decoda_name");
117 485
486#if KEEPER_MODEL == KEEPER_MODEL_C
487 // create the fifos table in the keeper state
488 lua_pushlightuserdata( K, fifos_key);
489 lua_newtable( K);
490 lua_rawset( K, LUA_REGISTRYINDEX);
491#endif // KEEPER_MODEL == KEEPER_MODEL_C
492
493#if KEEPER_MODEL == KEEPER_MODEL_LUA
118 // use package.loaders[2] to find keeper microcode 494 // use package.loaders[2] to find keeper microcode
119 lua_getglobal( K, "package"); // package 495 lua_getglobal( K, "package"); // package
120 lua_getfield( K, -1, "loaders"); // package package.loaders 496 lua_getfield( K, -1, "loaders"); // package package.loaders
@@ -132,6 +508,7 @@ char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create)
132 } // package package.loaders 508 } // package package.loaders
133 STACK_MID( K, 2); 509 STACK_MID( K, 2);
134 lua_pop( K, 2); 510 lua_pop( K, 2);
511#endif // KEEPER_MODEL == KEEPER_MODEL_LUA
135 STACK_END( K, 0) 512 STACK_END( K, 0)
136 MUTEX_INIT( &GKeepers[i].lock_); 513 MUTEX_INIT( &GKeepers[i].lock_);
137 GKeepers[i].L = K; 514 GKeepers[i].L = K;
@@ -207,7 +584,7 @@ struct s_Keeper *keeper_acquire( const void *ptr)
207 * 584 *
208 * Pointers are often aligned by 8 or so - ignore the low order bits 585 * Pointers are often aligned by 8 or so - ignore the low order bits
209 */ 586 */
210 unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers; 587 unsigned int i= ((uintptr_t)(ptr) >> 3) % GNbKeepers;
211 struct s_Keeper *K= &GKeepers[i]; 588 struct s_Keeper *K= &GKeepers[i];
212 589
213 MUTEX_LOCK( &K->lock_); 590 MUTEX_LOCK( &K->lock_);
@@ -259,16 +636,15 @@ void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel
259* 636*
260* Returns: number of return values (pushed to 'L') or -1 in case of error 637* Returns: number of return values (pushed to 'L') or -1 in case of error
261*/ 638*/
262int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index) 639int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index)
263{ 640{
264 int const args = starting_index ? (lua_gettop(L) - starting_index +1) : 0; 641 int const args = starting_index ? (lua_gettop( L) - starting_index + 1) : 0;
265 int const Ktos = lua_gettop(K); 642 int const Ktos = lua_gettop( K);
266 int retvals = -1; 643 int retvals = -1;
267 644
268 STACK_GROW( K, 2); 645 STACK_GROW( K, 2);
269 646
270 lua_getglobal( K, func_name); 647 PUSH_KEEPER_FUNC( K, _func);
271 ASSERT_L( lua_isfunction(K, -1));
272 648
273 lua_pushlightuserdata( K, linda); 649 lua_pushlightuserdata( K, linda);
274 650