summaryrefslogtreecommitdiff
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
parenta9075ff6cf43e99cee994f5e77d0e1e54cb8dbac (diff)
downloadlanes-f0b1c6d629464c0a59ac78382d86f434e74c2162.tar.gz
lanes-f0b1c6d629464c0a59ac78382d86f434e74c2162.tar.bz2
lanes-f0b1c6d629464c0a59ac78382d86f434e74c2162.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()
-rw-r--r--ABOUT2
-rw-r--r--CHANGES4
-rw-r--r--COPYRIGHT2
-rw-r--r--Makefile3
-rw-r--r--docs/index.html6
-rw-r--r--src/keeper.c390
-rw-r--r--src/keeper.h25
-rw-r--r--src/lanes-keeper.lua2
-rw-r--r--src/lanes.c31
9 files changed, 437 insertions, 28 deletions
diff --git a/ABOUT b/ABOUT
index 260fb5c..258ca57 100644
--- a/ABOUT
+++ b/ABOUT
@@ -3,7 +3,7 @@ Lua Lanes
3--------- 3---------
4 4
5Lanes is a lightweight, native, lazy evaluating multithreading library for 5Lanes is a lightweight, native, lazy evaluating multithreading library for
6Lua 5.1. It allows efficient use of multicore processors in Lua, by passing 6Lua 5.1 and Lua 5.2. It allows efficient use of multicore processors in Lua, by passing
7function calls into separate OS threads, and separate Lua states. 7function calls into separate OS threads, and separate Lua states.
8 8
9No locking of the threads is needed, only launching and waiting for (with an 9No locking of the threads is needed, only launching and waiting for (with an
diff --git a/CHANGES b/CHANGES
index 30f73c2..cc7b4a2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 45: BGe 21-Aug-2012
4 * keeper internals implemented in C instead of Lua for better performances
5 * fixed arguments checks in linda:limit() and linda:set()
6
3CHANGE 44: BGe 13-Aug-2012 7CHANGE 44: BGe 13-Aug-2012
4 * lanes code updated to build against Lua 5.1 and Lua 5.2 8 * lanes code updated to build against Lua 5.1 and Lua 5.2
5 * removed the search for MSVCR80.DLL when building for MinGW32 since it no longer seems to be necessary 9 * removed the search for MSVCR80.DLL when building for MinGW32 since it no longer seems to be necessary
diff --git a/COPYRIGHT b/COPYRIGHT
index 2fdb982..615a79b 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -7,7 +7,7 @@ For details and rationale, see http://www.lua.org/license.html
7=============================================================================== 7===============================================================================
8 8
9Copyright (C) 2007-11 Asko Kauppi, <akauppi@gmail.com> 9Copyright (C) 2007-11 Asko Kauppi, <akauppi@gmail.com>
10Copyright (C) 2010-11 Benoit Germain, <bnt.germain@gmail.com> 10Copyright (C) 2010-12 Benoit Germain, <bnt.germain@gmail.com>
11 11
12Permission is hereby granted, free of charge, to any person obtaining a copy 12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal 13of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index c5c41b1..261504d 100644
--- a/Makefile
+++ b/Makefile
@@ -197,11 +197,10 @@ LUA_SHAREDIR=$(DESTDIR)/share/lua/5.1
197# 197#
198# AKa 17-Oct: changed to use 'install -m 644' and 'cp -p' 198# AKa 17-Oct: changed to use 'install -m 644' and 'cp -p'
199# 199#
200install: $(_TARGET_SO) src/lanes.lua src/lanes-keeper.lua 200install: $(_TARGET_SO) src/lanes.lua
201 mkdir -p $(LUA_LIBDIR) $(LUA_LIBDIR)/lanes $(LUA_SHAREDIR) 201 mkdir -p $(LUA_LIBDIR) $(LUA_LIBDIR)/lanes $(LUA_SHAREDIR)
202 install -m 644 $(_TARGET_SO) $(LUA_LIBDIR)/lanes 202 install -m 644 $(_TARGET_SO) $(LUA_LIBDIR)/lanes
203 cp -p src/lanes.lua $(LUA_SHAREDIR) 203 cp -p src/lanes.lua $(LUA_SHAREDIR)
204 cp -p src/lanes-keeper.lua $(LUA_SHAREDIR)
205 204
206 205
207#--- Packaging --- 206#--- Packaging ---
diff --git a/docs/index.html b/docs/index.html
index 4e37fe6..84ae5c0 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -56,7 +56,7 @@
56 56
57<p><br/><font size="-1"><i>Copyright &copy; 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i> 57<p><br/><font size="-1"><i>Copyright &copy; 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i>
58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1 and 5.2. 58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1 and 5.2.
59 </p><p>This document was revised on 13-Aug-12, and applies to version 3.1.6 59 </p><p>This document was revised on 21-Aug-12, and applies to version 3.2.0
60</font></p> 60</font></p>
61 61
62</center> 62</center>
@@ -147,7 +147,7 @@
147details and limitations. 147details and limitations.
148</p> 148</p>
149 149
150<p>To install Lanes, all you need are the <tt>lanes.lua</tt> <tt>lanes-keeper.lua</tt> and <tt>lanes/core.so|dll</tt> 150<p>To install Lanes, all you need are the <tt>lanes.lua</tt> and <tt>lanes/core.so|dll</tt>
151files to be reachable by Lua (see LUA_PATH, LUA_CPATH). 151files to be reachable by Lua (see LUA_PATH, LUA_CPATH).
152 152
153Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management. 153Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management.
@@ -1070,7 +1070,7 @@ Here are some things one should consider, if best performance is vital:
1070 <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity. 1070 <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity.
1071 If you are using a lot of Linda objects, 1071 If you are using a lot of Linda objects,
1072 it may be useful to try having more of these keeper states. By default, 1072 it may be useful to try having more of these keeper states. By default,
1073 only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail. 1073 only one is used (see <tt>lanes.configure()</tt>).
1074 </li> 1074 </li>
1075</ul> 1075</ul>
1076</p> 1076</p>
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
diff --git a/src/keeper.h b/src/keeper.h
index 6c4c6f9..a0ea8c5 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -13,7 +13,30 @@ void populate_keepers( lua_State *L);
13struct s_Keeper *keeper_acquire( const void *ptr); 13struct s_Keeper *keeper_acquire( const void *ptr);
14void keeper_release( struct s_Keeper *K); 14void keeper_release( struct s_Keeper *K);
15void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); 15void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel);
16int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index);
17 16
17#define KEEPER_MODEL_LUA 1
18#define KEEPER_MODEL_C 2
19#define KEEPER_MODEL KEEPER_MODEL_C
20
21#if KEEPER_MODEL == KEEPER_MODEL_LUA
22typedef char const* keeper_api_t;
23#define KEEPER_API( _op) #_op
24#define PUSH_KEEPER_FUNC( K, _api) lua_getglobal( K, _api)
25#elif KEEPER_MODEL == KEEPER_MODEL_C
26typedef lua_CFunction keeper_api_t;
27#define KEEPER_API( _op) keepercall_ ## _op
28#define PUSH_KEEPER_FUNC lua_pushcfunction
29// lua_Cfunctions to run inside a keeper state (formerly implemented in Lua)
30int keepercall_clear( lua_State* L);
31int keepercall_send( lua_State* L);
32int keepercall_receive( lua_State* L);
33int keepercall_receive_batched( lua_State* L);
34int keepercall_limit( lua_State* L);
35int keepercall_get( lua_State* L);
36int keepercall_set( lua_State* L);
37int keepercall_count( lua_State* L);
38#endif // KEEPER_MODEL
39
40int keeper_call( lua_State *K, keeper_api_t _func, lua_State *L, void *linda, uint_t starting_index);
18 41
19#endif // __keeper_h__ \ No newline at end of file 42#endif // __keeper_h__ \ No newline at end of file
diff --git a/src/lanes-keeper.lua b/src/lanes-keeper.lua
index 1f17599..b07d6a9 100644
--- a/src/lanes-keeper.lua
+++ b/src/lanes-keeper.lua
@@ -2,6 +2,8 @@
2-- KEEPER.LUA 2-- KEEPER.LUA
3-- 3--
4-- Keeper state logic 4-- Keeper state logic
5-- DEPRECATED BY THE EQUIVALENT C IMPLEMENTATION, KEPT FOR REFERENCE ONLY
6-- SHOULD NOT BE PART OF THE INSTALLATION ANYMORE
5-- 7--
6-- This code is read in for each "keeper state", which are the hidden, inter- 8-- This code is read in for each "keeper state", which are the hidden, inter-
7-- mediate data stores used by Lanes inter-state communication objects. 9-- mediate data stores used by Lanes inter-state communication objects.
diff --git a/src/lanes.c b/src/lanes.c
index 8f5768f..9f455b2 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -51,7 +51,7 @@
51 * ... 51 * ...
52 */ 52 */
53 53
54char const* VERSION = "3.1.6"; 54char const* VERSION = "3.2.0";
55 55
56/* 56/*
57=============================================================================== 57===============================================================================
@@ -309,7 +309,7 @@ LUAG_FUNC( linda_send)
309 for( ;;) 309 for( ;;)
310 { 310 {
311 STACK_MID(KL, 0) 311 STACK_MID(KL, 0)
312 pushed = keeper_call( KL, "send", L, linda, key_i); 312 pushed = keeper_call( KL, KEEPER_API( send), L, linda, key_i);
313 if( pushed < 0) 313 if( pushed < 0)
314 { 314 {
315 break; 315 break;
@@ -410,7 +410,7 @@ LUAG_FUNC( linda_receive)
410 struct s_Linda *linda = lua_toLinda( L, 1); 410 struct s_Linda *linda = lua_toLinda( L, 1);
411 int pushed, expected_pushed_min, expected_pushed_max; 411 int pushed, expected_pushed_min, expected_pushed_max;
412 bool_t cancel = FALSE; 412 bool_t cancel = FALSE;
413 char *keeper_receive; 413 keeper_api_t keeper_receive;
414 414
415 time_d timeout = -1.0; 415 time_d timeout = -1.0;
416 uint_t key_i = 2; 416 uint_t key_i = 2;
@@ -440,7 +440,7 @@ LUAG_FUNC( linda_receive)
440 // make sure the keys are of a valid type 440 // make sure the keys are of a valid type
441 check_key_types( L, key_i, key_i); 441 check_key_types( L, key_i, key_i);
442 // receive multiple values from a single slot 442 // receive multiple values from a single slot
443 keeper_receive = "receive_batched"; 443 keeper_receive = KEEPER_API( receive_batched);
444 // we expect a user-defined amount of return value 444 // we expect a user-defined amount of return value
445 expected_pushed_min = (int)luaL_checkinteger( L, key_i + 1); 445 expected_pushed_min = (int)luaL_checkinteger( L, key_i + 1);
446 expected_pushed_max = (int)luaL_optinteger( L, key_i + 2, expected_pushed_min); 446 expected_pushed_max = (int)luaL_optinteger( L, key_i + 2, expected_pushed_min);
@@ -454,7 +454,7 @@ LUAG_FUNC( linda_receive)
454 // make sure the keys are of a valid type 454 // make sure the keys are of a valid type
455 check_key_types( L, key_i, lua_gettop( L)); 455 check_key_types( L, key_i, lua_gettop( L));
456 // receive a single value, checking multiple slots 456 // receive a single value, checking multiple slots
457 keeper_receive = "receive"; 457 keeper_receive = KEEPER_API( receive);
458 // we expect a single (value, key) pair of returned values 458 // we expect a single (value, key) pair of returned values
459 expected_pushed_min = expected_pushed_max = 2; 459 expected_pushed_min = expected_pushed_max = 2;
460 } 460 }
@@ -558,6 +558,7 @@ LUAG_FUNC( linda_set)
558 struct s_Linda *linda = lua_toLinda( L, 1); 558 struct s_Linda *linda = lua_toLinda( L, 1);
559 bool_t has_value = !lua_isnil( L, 3); 559 bool_t has_value = !lua_isnil( L, 3);
560 luaL_argcheck( L, linda, 1, "expected a linda object!"); 560 luaL_argcheck( L, linda, 1, "expected a linda object!");
561 luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments");
561 562
562 // make sure the key is of a valid type 563 // make sure the key is of a valid type
563 check_key_types( L, 2, 2); 564 check_key_types( L, 2, 2);
@@ -566,7 +567,7 @@ LUAG_FUNC( linda_set)
566 int pushed; 567 int pushed;
567 struct s_Keeper *K = keeper_acquire( linda); 568 struct s_Keeper *K = keeper_acquire( linda);
568 // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() 569 // no nil->sentinel toggling, we really clear the linda contents for the given key with a set()
569 pushed = keeper_call( K->L, "set", L, linda, 2); 570 pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2);
570 if( pushed >= 0) // no error? 571 if( pushed >= 0) // no error?
571 { 572 {
572 ASSERT_L( pushed == 0); 573 ASSERT_L( pushed == 0);
@@ -606,7 +607,7 @@ LUAG_FUNC( linda_count)
606 607
607 { 608 {
608 struct s_Keeper *K = keeper_acquire( linda); 609 struct s_Keeper *K = keeper_acquire( linda);
609 pushed = keeper_call( K->L, "count", L, linda, 2); 610 pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2);
610 keeper_release( K); 611 keeper_release( K);
611 if( pushed < 0) 612 if( pushed < 0)
612 { 613 {
@@ -634,7 +635,7 @@ LUAG_FUNC( linda_get)
634 635
635 { 636 {
636 struct s_Keeper *K = keeper_acquire( linda); 637 struct s_Keeper *K = keeper_acquire( linda);
637 pushed = keeper_call( K->L, "get", L, linda, 2); 638 pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2);
638 ASSERT_L( pushed==0 || pushed==1 ); 639 ASSERT_L( pushed==0 || pushed==1 );
639 if( pushed > 0) 640 if( pushed > 0)
640 { 641 {
@@ -659,15 +660,19 @@ LUAG_FUNC( linda_get)
659*/ 660*/
660LUAG_FUNC( linda_limit) 661LUAG_FUNC( linda_limit)
661{ 662{
662 struct s_Linda *linda= lua_toLinda( L, 1 ); 663 struct s_Linda* linda= lua_toLinda( L, 1 );
663 664
664 luaL_argcheck( L, linda, 1, "expected a linda object!"); 665 luaL_argcheck( L, linda, 1, "expected a linda object!");
666 // make sure we got a key and a limit
667 luaL_argcheck( L, lua_gettop( L) == 3, 2, "wrong number of arguments");
668 // make sure we got a numeric limit
669 luaL_checknumber( L, 3);
665 // make sure the key is of a valid type 670 // make sure the key is of a valid type
666 check_key_types( L, 2, 2); 671 check_key_types( L, 2, 2);
667 672
668 { 673 {
669 struct s_Keeper *K = keeper_acquire( linda); 674 struct s_Keeper* K = keeper_acquire( linda);
670 int pushed = keeper_call( K->L, "limit", L, linda, 2); 675 int pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2);
671 ASSERT_L( pushed <= 0); // either error or no return values 676 ASSERT_L( pushed <= 0); // either error or no return values
672 keeper_release( K); 677 keeper_release( K);
673 // must trigger error after keeper state has been released 678 // must trigger error after keeper state has been released
@@ -825,8 +830,8 @@ static void linda_id( lua_State *L, char const * const which)
825 K= keeper_acquire(s); 830 K= keeper_acquire(s);
826 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) 831 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
827 { 832 {
828 keeper_call( K->L, "clear", L, s, 0 ); 833 keeper_call( K->L, KEEPER_API( clear), L, s, 0 );
829 keeper_release(K); 834 keeper_release( K);
830 } 835 }
831 836
832 /* There aren't any lanes waiting on these lindas, since all proxies 837 /* There aren't any lanes waiting on these lindas, since all proxies