diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2012-08-22 21:36:37 +0200 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2012-08-22 21:36:37 +0200 |
commit | f0b1c6d629464c0a59ac78382d86f434e74c2162 (patch) | |
tree | e6788f8e7c0e859cd5f8d9254a922e187d9e7938 /src/keeper.c | |
parent | a9075ff6cf43e99cee994f5e77d0e1e54cb8dbac (diff) | |
download | lanes-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.c | 390 |
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 | |||
58 | typedef 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 | ||
66 | static 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} | ||
82 | static 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 | ||
96 | static 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 | ||
115 | static 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) | ||
127 | static 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] | ||
146 | static void* const fifos_key = (void*) prepare_fifo_access; | ||
147 | static 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 | ||
171 | int 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 | ||
186 | int 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 | ||
222 | int 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] | ||
256 | int 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 | ||
283 | int 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] | ||
305 | int 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 | ||
334 | int 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 [, ...]] | ||
353 | int 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 | */ |
262 | int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index) | 639 | int 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 | ||